|
1 |
| -<h1 align="center">SQLx</h1> |
2 |
| -<div align="center"> |
3 |
| - <strong> |
4 |
| - 🧰 The Rust SQL Toolkit |
5 |
| - </strong> |
6 |
| -</div> |
| 1 | +# Initial page |
7 | 2 |
|
8 |
| -<br /> |
9 |
| - |
10 |
| -<div align="center"> |
11 |
| - <!-- Github Actions --> |
12 |
| - <img src="https://img.shields.io/github/workflow/status/launchbadge/sqlx/Rust?style=flat-square" alt="actions status" /> |
13 |
| - <!-- Version --> |
14 |
| - <a href="https://crates.io/crates/sqlx"> |
15 |
| - <img src="https://img.shields.io/crates/v/sqlx.svg?style=flat-square" |
16 |
| - alt="Crates.io version" /> |
17 |
| - </a> |
18 |
| - <!-- Discord --> |
19 |
| - <a href="https://discord.gg/uuruzJ7"> |
20 |
| - <img src="https://img.shields.io/discord/665528275556106240?style=flat-square" alt="chat" /> |
21 |
| - </a> |
22 |
| - <!-- Docs --> |
23 |
| - <a href="https://docs.rs/sqlx"> |
24 |
| - <img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square" |
25 |
| - alt="docs.rs docs" /> |
26 |
| - </a> |
27 |
| - <!-- Downloads --> |
28 |
| - <a href="https://crates.io/crates/sqlx"> |
29 |
| - <img src="https://img.shields.io/crates/d/sqlx.svg?style=flat-square" |
30 |
| - alt="Download" /> |
31 |
| - </a> |
32 |
| -</div> |
33 |
| - |
34 |
| -<div align="center"> |
35 |
| - <h4> |
36 |
| - <a href="#install"> |
37 |
| - Install |
38 |
| - </a> |
39 |
| - <span> | </span> |
40 |
| - <a href="#usage"> |
41 |
| - Usage |
42 |
| - </a> |
43 |
| - <span> | </span> |
44 |
| - <a href="https://docs.rs/sqlx"> |
45 |
| - Docs |
46 |
| - </a> |
47 |
| - </h4> |
48 |
| -</div> |
49 |
| - |
50 |
| -<br /> |
51 |
| - |
52 |
| -<div align="center"> |
53 |
| - <sub>Built with ❤️ by <a href="https://launchbadge.com">The LaunchBadge team</a></sub> |
54 |
| -</div> |
55 |
| - |
56 |
| -<br /> |
57 |
| - |
58 |
| -SQLx is an async, pure Rust<sub>†</sub> SQL crate featuring compile-time checked queries without a DSL. |
59 |
| - |
60 |
| - * **Truly Asynchronous**. Built from the ground-up using async/await for maximum concurrency. |
61 |
| - |
62 |
| - * **Type-safe SQL** (if you want it) without DSLs. Use the `query!()` macro to check your SQL and bind parameters at |
63 |
| - compile time. (You can still use dynamic SQL queries if you like.) |
64 |
| - |
65 |
| - * **Database Agnostic**. Support for [PostgreSQL], [MySQL], and [SQLite]. |
66 |
| - |
67 |
| - * **Pure Rust**. The Postgres and MySQL/MariaDB drivers are written in pure Rust using **zero** unsafe<sub>††</sub> code. |
68 |
| - |
69 |
| - * **Runtime Agnostic**. Works on [async-std](https://crates.io/crates/async-std) or [tokio](https://crates.io/crates/tokio) with the `runtime-async-std` or `runtime-tokio` cargo feature flag. |
70 |
| - |
71 |
| -<sub><sup>† The SQLite driver uses the libsqlite3 C library as SQLite is an embedded database (the only way |
72 |
| -we could be pure Rust for SQLite is by porting _all_ of SQLite to Rust).</sup></sub> |
73 |
| - |
74 |
| -<sub><sup>†† SQLx uses `#![forbid(unsafe_code)]` unless the `sqlite` feature is enabled. As the SQLite driver interacts |
75 |
| -with C, those interactions are `unsafe`.</sup></sub> |
76 |
| - |
77 |
| -[PostgreSQL]: http://postgresql.org/ |
78 |
| -[SQLite]: https://sqlite.org/ |
79 |
| -[MySQL]: https://www.mysql.com/ |
80 |
| - |
81 |
| ---- |
82 |
| - |
83 |
| - * Cross-platform. Being native Rust, SQLx will compile anywhere Rust is supported. |
84 |
| - |
85 |
| - * Built-in connection pooling with `sqlx::Pool`. |
86 |
| - |
87 |
| - * Row streaming. Data is read asynchronously from the database and decoded on-demand. |
88 |
| - |
89 |
| - * Automatic statement preparation and caching. When using the high-level query API (`sqlx::query`), statements are |
90 |
| - prepared and cached per-connection. |
91 |
| - |
92 |
| - * Simple (unprepared) query execution including fetching results into the same `Row` types used by |
93 |
| - the high-level API. Supports batch execution and returning results from all statements. |
94 |
| - |
95 |
| - * Transport Layer Security (TLS) where supported ([MySQL] and [PostgreSQL]). |
96 |
| - |
97 |
| - * Asynchronous notifications using `LISTEN` and `NOTIFY` for [PostgreSQL]. |
98 |
| - |
99 |
| - * Nested transactions with support for save points. |
100 |
| - |
101 |
| -## Install |
102 |
| - |
103 |
| -SQLx is compatible with the [`async-std`] and [`tokio`] runtimes. |
104 |
| - |
105 |
| -[`async-std`]: https://github.com/async-rs/async-std |
106 |
| -[`tokio`]: https://github.com/tokio-rs/tokio |
107 |
| - |
108 |
| -**async-std** |
109 |
| - |
110 |
| -```toml |
111 |
| -# Cargo.toml |
112 |
| -[dependencies] |
113 |
| -sqlx = "0.3" |
| 3 | +{% tabs %} |
| 4 | +{% tab title="Postgres" %} |
| 5 | +```text |
| 6 | +SELECT id, name |
| 7 | +FROM table |
| 8 | +WHERE email = $1 |
114 | 9 | ```
|
| 10 | +{% endtab %} |
115 | 11 |
|
116 |
| -**tokio** |
117 |
| - |
118 |
| -```toml |
119 |
| -# Cargo.toml |
120 |
| -[dependencies] |
121 |
| -sqlx = { version = "0.3", default-features = false, features = [ "runtime-tokio", "macros" ] } |
| 12 | +{% tab title="MySQL" %} |
| 13 | +```text |
| 14 | +SELECT id, name |
| 15 | +FROM table |
| 16 | +WHERE email = ? |
122 | 17 | ```
|
| 18 | +{% endtab %} |
| 19 | +{% endtabs %} |
123 | 20 |
|
124 |
| -#### Cargo Feature Flags |
125 |
| - |
126 |
| - * `runtime-async-std` (on by default): Use the `async-std` runtime. |
127 |
| - |
128 |
| - * `runtime-tokio`: Use the `tokio` runtime. Mutually exclusive with the `runtime-async-std` feature. |
129 |
| - |
130 |
| - * `postgres`: Add support for the Postgres database server. |
131 |
| - |
132 |
| - * `mysql`: Add support for the MySQL (and MariaDB) database server. |
133 |
| - |
134 |
| - * `sqlite`: Add support for the self-contained [SQLite](https://sqlite.org/) database engine. |
135 |
| - |
136 |
| - * `uuid`: Add support for UUID (in Postgres). |
137 |
| - |
138 |
| - * `chrono`: Add support for date and time types from `chrono`. |
139 |
| - |
140 |
| - * `time`: Add support for date and time types from `time` crate (alternative to `chrono`, prefered by `query!` macro, if both enabled) |
141 |
| - |
142 |
| - * `bigdecimal`: Add support for `NUMERIC` using the `bigdecimal` crate. |
143 |
| - |
144 |
| - * `ipnetwork`: Add support for `INET` and `CIDR` (in postgres) using the `ipnetwork` crate. |
145 |
| - |
146 |
| - * `json`: Add support for `JSON` and `JSONB` (in postgres) using the `serde_json` crate. |
147 |
| - |
148 |
| - * `tls`: Add support for TLS connections. |
149 |
| - |
150 |
| -## Usage |
151 |
| - |
152 |
| -### Quickstart |
153 |
| - |
154 |
| -```rust |
155 |
| -use std::env; |
156 |
| - |
157 |
| -use sqlx::postgres::PgPool; |
158 |
| -// use sqlx::mysql::MySqlPool; |
159 |
| -// etc. |
160 |
| - |
161 |
| -#[async_std::main] // or #[tokio::main] |
162 |
| -async fn main() -> Result<(), sqlx::Error> { |
163 |
| - // Create a connection pool |
164 |
| - let pool = PgPool::builder() |
165 |
| - .max_size(5) // maximum number of connections in the pool |
166 |
| - .build(&env::var("DATABASE_URL")?).await?; |
167 |
| - |
168 |
| - // Make a simple query to return the given parameter |
169 |
| - let row: (i64,) = sqlx::query_as("SELECT $1") |
170 |
| - .bind(150_i64) |
171 |
| - .fetch_one(&pool).await?; |
172 |
| - |
173 |
| - assert_eq!(row.0, 150); |
174 |
| - |
175 |
| - Ok(()) |
176 |
| -} |
| 21 | +{% tabs %} |
| 22 | +{% tab title="Postgres" %} |
| 23 | +```text |
| 24 | +SELECT id, name |
| 25 | +FROM other_table |
| 26 | +WHERE name = $1 |
177 | 27 | ```
|
| 28 | +{% endtab %} |
178 | 29 |
|
179 |
| -### Connecting |
180 |
| - |
181 |
| -A single connection can be established using any of the database connection types and calling `connect()`. |
182 |
| - |
183 |
| -```rust |
184 |
| -use sqlx::Connect; |
185 |
| - |
186 |
| -let conn = SqliteConnection::connect("sqlite::memory:").await?; |
| 30 | +{% tab title="MySQL" %} |
| 31 | +```text |
| 32 | +SELECT id, name |
| 33 | +FROM table |
| 34 | +WHERE email = ? |
187 | 35 | ```
|
| 36 | +{% endtab %} |
| 37 | +{% endtabs %} |
188 | 38 |
|
189 |
| -Generally, you will want to instead create a connection pool (`sqlx::Pool`) in order for your application to |
190 |
| -regulate how many server-side connections it's using. |
191 |
| - |
192 |
| -```rust |
193 |
| -let pool = MySqlPool::new("mysql://user:pass@host/database").await?; |
194 |
| -``` |
195 |
| - |
196 |
| -### Querying |
197 |
| - |
198 |
| -In SQL, queries can be separated into prepared (parameterized) or unprepared (simple). Prepared queries have their |
199 |
| -query plan _cached_, use a binary mode of communication (lower bandwidth and faster decoding), and utilize parameters |
200 |
| -to avoid SQL injection. Unprepared queries are simple and intended only for use case where a prepared statement |
201 |
| -will not work, such as various database commands (e.g., `PRAGMA` or `SET` or `BEGIN`). |
202 |
| - |
203 |
| -SQLx supports all operations with both types of queries. In SQLx, a `&str` is treated as an unprepared query |
204 |
| -and a `Query` or `QueryAs` struct is treated as a prepared query. |
205 |
| - |
206 |
| -```rust |
207 |
| -// low-level, Executor trait |
208 |
| -conn.execute("BEGIN").await?; // unprepared, simple query |
209 |
| -conn.execute(sqlx::query("DELETE FROM table")).await?; // prepared, cached query |
210 |
| -``` |
211 |
| - |
212 |
| -We should prefer to use the high level, `query` interface whenever possible. To make this easier, there are finalizers |
213 |
| -on the type to avoid the need to wrap with an executor. |
214 |
| - |
215 |
| -```rust |
216 |
| -sqlx::query("DELETE FROM table").execute(&mut conn).await?; |
217 |
| -sqlx::query("DELETE FROM table").execute(&pool).await?; |
218 |
| -``` |
219 |
| - |
220 |
| -The `execute` query finalizer returns the number of affected rows, if any, and drops all received results. |
221 |
| -In addition, there are `fetch`, `fetch_one`, `fetch_optional`, `fetch_all`, and `fetch_scalar` to receive results. |
222 |
| - |
223 |
| -The `Query` type returned from `sqlx::query` will return `Row<'conn>` from the database. Column values can be accessed |
224 |
| -by ordinal or by name with `row.get()`. As the `Row` retains an immutable borrow on the connection, only one |
225 |
| -`Row` may exist at a time. |
226 |
| - |
227 |
| -The `fetch` query finalizer returns a stream-like type that iterates through the rows in the result sets. |
228 |
| - |
229 |
| -```rust |
230 |
| -let mut cursor = sqlx::query("SELECT * FROM users WHERE email = ?") |
231 |
| - .bind(email) |
232 |
| - .fetch(&mut conn).await?; |
233 |
| - |
234 |
| -while let Some(row) = cursor.next().await? { |
235 |
| - // map the row into a user-defined domain type |
236 |
| -} |
237 |
| -``` |
238 |
| - |
239 |
| -To assist with mapping the row into a domain type, there are two idioms that may be used: |
240 |
| - |
241 |
| -```rust |
242 |
| -let mut stream = sqlx::query("SELECT * FROM users") |
243 |
| - .map(|row: PgRow| { |
244 |
| - // map the row into a user-defined domain type |
245 |
| - }) |
246 |
| - .fetch(&mut conn); |
247 |
| -``` |
248 |
| - |
249 |
| -```rust |
250 |
| -#[derive(sqlx::FromRow)] |
251 |
| -struct User { name: String, id: i64 } |
252 |
| - |
253 |
| -let mut stream = sqlx::query_as::<_, User>("SELECT * FROM users WHERE email = ? OR name = ?") |
254 |
| - .bind(user_email) |
255 |
| - .bind(user_name) |
256 |
| - .fetch(&mut conn); |
257 |
| -``` |
258 |
| - |
259 |
| -Instead of a stream of results, we can use `fetch_one` or `fetch_optional` to request one required or optional result |
260 |
| -from the database. |
261 |
| - |
262 |
| -### Compile-time verification |
263 |
| - |
264 |
| -We can use the macro, `sqlx::query!` to achieve compile-time syntactic and semantic verification of the SQL, with |
265 |
| -an output to an anonymous record type where each SQL column is a Rust field (using raw identifiers where needed). |
266 |
| - |
267 |
| -```rust |
268 |
| -let countries = sqlx::query!( |
269 |
| - " |
270 |
| -SELECT country, COUNT(*) as count |
271 |
| -FROM users |
272 |
| -GROUP BY country |
273 |
| -WHERE organization = ? |
274 |
| - ", |
275 |
| - organization |
276 |
| - ) |
277 |
| - .fetch_all(&pool) // -> Vec<{ country: String, count: i64 }> |
278 |
| - .await?; |
279 |
| - |
280 |
| -// countries[0].country |
281 |
| -// countries[0].count |
282 |
| -``` |
283 |
| - |
284 |
| -Differences from `query()`: |
285 |
| - |
286 |
| - * The input (or bind) parameters must be given all at once (and they are compile-time validated to be |
287 |
| - the right number and the right type). |
288 |
| - |
289 |
| - * The output type is an anonymous record. In the above example the type would be similar to: |
290 |
| - |
291 |
| - ```rust |
292 |
| - { country: String, count: i64 } |
293 |
| - ``` |
294 |
| - |
295 |
| - * The `DATABASE_URL` environment variable must be set at build time to a database which it can prepare |
296 |
| - queries against; the database does not have to contain any data but must be the same |
297 |
| - kind (MySQL, Postgres, etc.) and have the same schema as the database you will be connecting to at runtime. |
298 |
| - |
299 |
| - For convenience, you can use a .env file to set DATABASE_URL so that you don't have to pass it every time: |
300 |
| - |
301 |
| - ``` |
302 |
| - DATABASE_URL=mysql://localhost/my_database |
303 |
| - ``` |
304 |
| - |
305 |
| -The biggest downside to `query!()` is that the output type cannot be named (due to Rust not |
306 |
| -officially supporting anonymous records). To address that, there is a `query_as!()` macro that is identical |
307 |
| -except that you can name the output type. |
308 |
| - |
309 |
| - |
310 |
| -```rust |
311 |
| -// no traits are needed |
312 |
| -struct Country { country: String, count: i64 } |
313 |
| - |
314 |
| -let countries = sqlx::query_as!(Country, |
315 |
| - " |
316 |
| -SELECT country, COUNT(*) as count |
317 |
| -FROM users |
318 |
| -GROUP BY country |
319 |
| -WHERE organization = ? |
320 |
| - ", |
321 |
| - organization |
322 |
| - ) |
323 |
| - .fetch_all() // -> Vec<Country> |
324 |
| - .await?; |
325 |
| - |
326 |
| -// countries[0].country |
327 |
| -// countries[0].count |
328 |
| -``` |
329 |
| - |
330 |
| -## Safety |
331 |
| - |
332 |
| -This crate uses `#![forbid(unsafe_code)]` to ensure everything is implemented in 100% Safe Rust. |
333 |
| - |
334 |
| -If the `sqlite` feature is enabled, this is downgraded to `#![deny(unsafe_code)]` with `#![allow(unsafe_code)]` on the |
335 |
| -`sqlx::sqlite` module. There are several places where we interact with the C SQLite API. We try to document each call for the invariants we're assuming. We absolutely welcome auditing of, and feedback on, our unsafe code usage. |
336 |
| - |
337 |
| -## License |
338 |
| - |
339 |
| -Licensed under either of |
340 |
| - |
341 |
| - * Apache License, Version 2.0 |
342 |
| - ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) |
343 |
| - * MIT license |
344 |
| - ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
345 |
| - |
346 |
| -at your option. |
347 | 39 |
|
348 |
| -## Contribution |
349 | 40 |
|
350 |
| -Unless you explicitly state otherwise, any contribution intentionally submitted |
351 |
| -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be |
352 |
| -dual licensed as above, without any additional terms or conditions. |
0 commit comments