|
1 | | -rust-postgres |
| 1 | +Rust-Postgres |
2 | 2 | ============= |
| 3 | +A native PostgreSQL driver for Rust. |
| 4 | + |
| 5 | +Overview |
| 6 | +======== |
| 7 | +Rust-Postgres is a pure-Rust frontend for the popular PostgreSQL database. It |
| 8 | +exposes a high level interface in the vein of JDBC or Go's `database/sql` |
| 9 | +package. |
| 10 | +```rust |
| 11 | +extern mod postgres; |
| 12 | + |
| 13 | +use postgres::PostgresConnection; |
| 14 | +use postgres::types::ToSql; |
| 15 | + |
| 16 | +#[deriving(ToStr)] |
| 17 | +struct Person { |
| 18 | + id: i32, |
| 19 | + name: ~str, |
| 20 | + awesome: bool, |
| 21 | + data: Option<~[u8]> |
| 22 | +} |
| 23 | + |
| 24 | +fn main() { |
| 25 | + let conn = PostgresConnection::connect("postgres://postgres@127.0.0.1"); |
| 26 | + |
| 27 | + conn.update("CREATE TABLE person ( |
| 28 | + id SERIAL PRIMARY KEY, |
| 29 | + name VARCHAR NOT NULL, |
| 30 | + awesome BOOL NOT NULL, |
| 31 | + data BYTEA |
| 32 | + )", []); |
| 33 | + let me = Person { |
| 34 | + id: 0, |
| 35 | + name: ~"Steven", |
| 36 | + awesome: true, |
| 37 | + data: None |
| 38 | + }; |
| 39 | + conn.update("INSERT INTO person (name, awesome, data) |
| 40 | + VALUES ($1, $2, $3)", |
| 41 | + [&me.name as &ToSql, &me.awesome as &ToSql, |
| 42 | + &me.data as &ToSql]); |
| 43 | + |
| 44 | + let stmt = conn.prepare("SELECT id, name, awesome, data FROM person"); |
| 45 | + for row in stmt.query([]) { |
| 46 | + let person = Person { |
| 47 | + id: row[0], |
| 48 | + name: row[1], |
| 49 | + awesome: row[2], |
| 50 | + data: row[3] |
| 51 | + }; |
| 52 | + println!("Found person {}", person.to_str()); |
| 53 | + } |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +Requirements |
| 58 | +============ |
| 59 | + |
| 60 | +* **Rust** - Rust-Postgres is developed against the *master* branch of the Rust |
| 61 | + repository. It will most likely not build against the releases on |
| 62 | + http://www.rust-lang.org. |
| 63 | + |
| 64 | +* **PostgreSQL 7.4 or later** - Rust-Postgres speaks version 3 of the |
| 65 | + PostgreSQL protocol, which corresponds to versions 7.4 and later. If your |
| 66 | + version of Postgres was compiled in the last decade, you should be okay. |
| 67 | + |
| 68 | +Usage |
| 69 | +===== |
| 70 | + |
| 71 | +Connecting |
| 72 | +---------- |
| 73 | +Connect to a Postgres server using the standard URI format: |
| 74 | +```rust |
| 75 | +let conn = PostgresConnection::connect("postgres://user:pass@host:port/database?arg1=val1&arg2=val2"); |
| 76 | +``` |
| 77 | +As the Rust standard library currently lacks DNS lookup functionality, `host` |
| 78 | +must currently be an IP address. |
| 79 | + |
| 80 | +`pass` may be omitted if not needed. `port` defaults to `5432` and `database` |
| 81 | +defaults to the value of `user` if not specified. The driver supports `trust`, |
| 82 | +`password` and `md5` authentication. |
| 83 | + |
| 84 | +Statement Preparation |
| 85 | +--------------------- |
| 86 | +Prepared statements can have parameters, represented as `$n` where `n` is an |
| 87 | +index into the parameter array starting from 1: |
| 88 | +```rust |
| 89 | +let stmt = conn.prepare("SELECT * FROM foo WHERE bar = $1 AND baz = $2"); |
| 90 | +``` |
| 91 | + |
| 92 | +Querying |
| 93 | +-------- |
| 94 | +A prepared statement can be executed with the `query` and `update` methods. |
| 95 | +Both methods take an array of parameters to bind to the query represented as |
| 96 | +`&ToSql` trait objects. `update` returns the number of rows affected by the |
| 97 | +query (or 0 if not applicable): |
| 98 | +``` |
| 99 | +let stmt = conn.prepare("UPDATE foo SET bar = $1 WHERE baz = $2"); |
| 100 | +let updates = stmt.update([&1i32 as &ToSql, & &"biz" as &ToSql]); |
| 101 | +println!("{} rows were updated", updates); |
| 102 | +``` |
| 103 | +`query` returns a result iterator. Fields of each row in the result can be |
| 104 | +accessed either by its index or their column name: |
| 105 | +```rust |
| 106 | +let stmt = conn.prepare("SELECT bar, baz FROM foo"); |
| 107 | +for row in stmt.query([]) { |
| 108 | + let bar: i32 = row[0]; |
| 109 | + let baz: ~str = row["baz"]; |
| 110 | + println!("bar: {}, baz: {}", bar, baz); |
| 111 | +} |
| 112 | +``` |
| 113 | +In addition, `PostgresConnection` has a utility `update` method which is useful |
| 114 | +if a statement is only going to be executed once: |
| 115 | +```rust |
| 116 | +let updates = conn.update("UPDATE foo SET bar = $1 WHERE baz = $2", |
| 117 | + [&1i32 as &ToSql, & &"biz" as &ToSql]); |
| 118 | +println!("{} rows were updated", updates); |
| 119 | +``` |
| 120 | + |
| 121 | +Transactions |
| 122 | +------------ |
| 123 | +Transactions are encapsulated by the `in_transaction` method. `in_transaction` |
| 124 | +takes a closure which is passed a `PostgresTransaction` object which has the |
| 125 | +functionality of a `PostgresConnection` as well as methods to control the |
| 126 | +result of the transaction: |
| 127 | +```rust |
| 128 | +do conn.in_transaction |trans| { |
| 129 | + trans.update(...); |
| 130 | + let stmt = trans.prepare(...); |
| 131 | + |
| 132 | + if a_bad_thing_happened { |
| 133 | + trans.set_rollback(); |
| 134 | + } |
| 135 | + |
| 136 | + if the_coast_is_clear { |
| 137 | + trans.set_commit(); |
| 138 | + } |
| 139 | +} |
| 140 | +``` |
| 141 | +A transaction will commit by default. Transactions cannot currently be nested. |
| 142 | + |
| 143 | +Error Handling |
| 144 | +-------------- |
| 145 | +The methods described above will fail if there is an error. For each of these |
| 146 | +methods, there is a second variant prefixed with `try_` which returns a |
| 147 | +`Result`: |
| 148 | +```rust |
| 149 | +match conn.try_update(query) { |
| 150 | + Ok(updates) => println!("{} rows were updated", updates), |
| 151 | + Err(err) => println!("An error occurred: {}", err.to_str()) |
| 152 | +} |
| 153 | +``` |
| 154 | + |
| 155 | +Type Correspondence |
| 156 | +------------------- |
| 157 | +Rust-Postgres enforces a strict correspondence between Rust types and Postgres |
| 158 | +types. The driver currently natively supports the following conversions: |
| 159 | + |
| 160 | +<table> |
| 161 | + <thead> |
| 162 | + <tr> |
| 163 | + <td>Rust Type</td> |
| 164 | + <td>Postgres Type</td> |
| 165 | + </tr> |
| 166 | + </thead> |
| 167 | + <tbody> |
| 168 | + <tr> |
| 169 | + <td>bool</td> |
| 170 | + <td>BOOL</td> |
| 171 | + </tr> |
| 172 | + <tr> |
| 173 | + <td>i8</td> |
| 174 | + <td>"char"</td> |
| 175 | + </tr> |
| 176 | + <tr> |
| 177 | + <td>i16</td> |
| 178 | + <td>SMALLINT</td> |
| 179 | + </tr> |
| 180 | + <tr> |
| 181 | + <td>i32</td> |
| 182 | + <td>INT</td> |
| 183 | + </tr> |
| 184 | + <tr> |
| 185 | + <td>i64</td> |
| 186 | + <td>BIGINT</td> |
| 187 | + </tr> |
| 188 | + <tr> |
| 189 | + <td>f32</td> |
| 190 | + <td>FLOAT4</td> |
| 191 | + </tr> |
| 192 | + <tr> |
| 193 | + <td>f64</td> |
| 194 | + <td>FLOAT8</td> |
| 195 | + </tr> |
| 196 | + <tr> |
| 197 | + <td>str</td> |
| 198 | + <td>VARCHAR, CHAR(n), TEXT</td> |
| 199 | + </tr> |
| 200 | + <tr> |
| 201 | + <td>[u8]</td> |
| 202 | + <td>BYTEA</td> |
| 203 | + </tr> |
| 204 | + <tr> |
| 205 | + <td>extra::json::Json</td> |
| 206 | + <td>JSON</td> |
| 207 | + </tr> |
| 208 | + <tr> |
| 209 | + <td>extra::uuid::Uuid</td> |
| 210 | + <td>UUID</td> |
| 211 | + </tr> |
| 212 | + </tbody> |
| 213 | +</table> |
| 214 | + |
| 215 | +More conversions can be defined by implementing the `ToSql` and `FromSql` |
| 216 | +traits. |
| 217 | + |
| 218 | +Development |
| 219 | +=========== |
| 220 | +Rust-Postgres is still under active development, so don't be surprised if APIs |
| 221 | +change and things break. If something's not working properly, file an issue or |
| 222 | +submit a pull request! |
0 commit comments