9.7 KiB
Rust-Postgres
A native PostgreSQL driver for Rust.
Documentation is available at http://sfackler.github.io/rust-postgres/doc/postgres/index.html.
Overview
Rust-Postgres is a pure-Rust frontend for the popular PostgreSQL database. It
exposes a high level interface in the vein of JDBC or Go's database/sql
package.
extern crate postgres;
extern crate time;
use time::Timespec;
use postgres::{PostgresConnection, NoSsl};
use postgres::types::ToSql;
struct Person {
id: i32,
name: ~str,
time_created: Timespec,
data: Option<Vec<u8>>
}
fn main() {
let conn = PostgresConnection::connect("postgres://postgres@localhost",
&NoSsl).unwrap();
conn.execute("CREATE TABLE person (
id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
time_created TIMESTAMP NOT NULL,
data BYTEA
)", []).unwrap();
let me = Person {
id: 0,
name: "Steven".to_owned(),
time_created: time::get_time(),
data: None
};
conn.execute("INSERT INTO person (name, time_created, data)
VALUES ($1, $2, $3)",
[&me.name as &ToSql, &me.time_created as &ToSql,
&me.data as &ToSql]).unwrap();
let stmt = conn.prepare("SELECT id, name, time_created, data FROM person")
.unwrap();
for row in stmt.query([]).unwrap() {
let person = Person {
id: row[1],
name: row[2],
time_created: row[3],
data: row[4]
};
println!("Found person {}", person.name);
}
}
Requirements
-
Rust - Rust-Postgres is developed against the master branch of the Rust repository. It will most likely not build against the releases on http://www.rust-lang.org.
-
PostgreSQL 7.4 or later - Rust-Postgres speaks version 3 of the PostgreSQL protocol, which corresponds to versions 7.4 and later. If your version of Postgres was compiled in the last decade, you should be okay.
Usage
Connecting
Connect to a Postgres server using the standard URI format:
let conn = try!(PostgresConnection::connect("postgres://user:pass@host:port/database?arg1=val1&arg2=val2",
&NoSsl));
pass
may be omitted if not needed. port
defaults to 5432
and database
defaults to the value of user
if not specified. The driver supports trust
,
password
, and md5
authentication.
Statement Preparation
Prepared statements can have parameters, represented as $n
where n
is an
index into the parameter array starting from 1:
let stmt = try!(conn.prepare("SELECT * FROM foo WHERE bar = $1 AND baz = $2"));
Querying
A prepared statement can be executed with the query
and execute
methods.
Both methods take an array of parameters to bind to the query represented as
&ToSql
trait objects. execute
returns the number of rows affected by the
query (or 0 if not applicable):
let stmt = conn.prepare("UPDATE foo SET bar = $1 WHERE baz = $2");
let updates = stmt.execute([&1i32 as &ToSql, & &"biz" as &ToSql]);
println!("{} rows were updated", updates);
query
returns an iterator over the rows returned from the database. The
fields in a row can be accessed either by their indices or their column names,
though access by index is more efficient. Like statement parameters, result
columns are one-indexed.
let stmt = try!(conn.prepare("SELECT bar, baz FROM foo"));
for row in try!(stmt.query([])) {
let bar: i32 = row[1];
let baz: ~str = row["baz"];
println!("bar: {}, baz: {}", bar, baz);
}
In addition, PostgresConnection
has a utility execute
method which is useful
if a statement is only going to be executed once:
let updates = try!(conn.execute("UPDATE foo SET bar = $1 WHERE baz = $2",
[&1i32 as &ToSql, & &"biz" as &ToSql]));
println!("{} rows were updated", updates);
Transactions
The transaction
method will start a new transaction. It returns a
PostgresTransaction
object which has the functionality of a
PostgresConnection
as well as methods to control the result of the
transaction:
let trans = try!(conn.transaction());
try!(trans.execute(...));
let stmt = try!(trans.prepare(...));
if a_bad_thing_happened {
trans.set_rollback();
}
if the_coast_is_clear {
trans.set_commit();
}
drop(trans);
The transaction will be active until the PostgresTransaction
object falls out
of scope. A transaction will commit by default. Nested transactions are
supported via savepoints.
Connection Pooling
A very basic fixed-size connection pool is provided in the pool
module. A
single pool can be shared across tasks and get_connection
will block until a
connection is available.
let pool = try!(PostgresConnectionPool::new("postgres://postgres@localhost",
NoSsl, 5));
for _ in range(0, 10) {
let pool = pool.clone();
spawn(proc() {
let conn = pool.get_connection();
conn.query(...).unwrap();
})
}
Type Correspondence
Rust-Postgres enforces a strict correspondence between Rust types and Postgres types. The driver currently supports the following conversions:
Rust Type | Postgres Type |
bool | BOOL |
i8 | "char" |
i16 | SMALLINT, SMALLSERIAL |
i32 | INT, SERIAL |
i64 | BIGINT, BIGSERIAL |
f32 | REAL |
f64 | DOUBLE PRECISION |
str | VARCHAR, CHAR(n), TEXT |
[u8]/Vec<u8> | BYTEA |
extra::json::Json | JSON |
extra::uuid::Uuid | UUID |
extra::time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
types::range::Range<i32> | INT4RANGE |
types::range::Range<i64> | INT8RANGE |
types::range::Range<Timespec> | TSRANGE, TSTZRANGE |
types::array::ArrayBase<Option<bool>> | BOOL[], BOOL[][], ... |
types::array::ArrayBase<Option<Vec<u8>>> | BYTEA[], BYTEA[][], ... |
types::array::ArrayBase<Option<i8>> | "char"[], "char"[][], ... |
types::array::ArrayBase<Option<i16>> | INT2[], INT2[][], ... |
types::array::ArrayBase<Option<i32>> | INT4[], INT4[][], ... |
types::array::ArrayBase<Option<~str>> | TEXT[], CHAR(n)[], VARCHAR[], TEXT[][], ... |
types::array::ArrayBase<Option<Json>> | JSON[], JSON[][], ... |
types::array::ArrayBase<Option<i64>> | INT8[], INT8[][], ... |
types::array::ArrayBase<Option<Timespec>> | TIMESTAMP[], TIMESTAMPTZ[], TIMESTAMP[][], ... |
types::array::ArrayBase<Option<f32>> | FLOAT4[], FLOAT4[][], ... |
types::array::ArrayBase<Option<f64>> | FLOAT8[], FLOAT8[][], ... |
types::array::ArrayBase<Option<Uuid>> | UUID[], UUID[][], ... |
types::array::ArrayBase<Option<Range<i32>>> | INT4RANGE[], INT4RANGE[][], ... |
types::array::ArrayBase<Option<Range<Timespec>>> | TSRANGE[], TSTZRANGE[], TSRANGE[][], ... |
types::array::ArrayBase<Option<Range<i64>>> | INT8RANGE[], INT8RANGE[][], ... |
std::hashmap::HashMap<~str, Option<~str>> | HSTORE |
More conversions can be defined by implementing the ToSql
and FromSql
traits.
Development
Like Rust itself, Rust-Postgres is still in the early stages of development, so don't be surprised if APIs change and things break. If something's not working properly, file an issue or submit a pull request!