[][src]Crate pleingres

A fully-asynchronous Postgres client. Postgres has a notion of "statements", which are named or unnamed SQL commands, and of "portals", where a portal is an instance of a result. All queries to the database follow the same sequence: parse, bind, execute, close (portal and/or statement).

Both statements and portals can be named or unnamed, although prototype code might be easier to write using only the query method of the Connection type, which does the correct sequence using the unnamed statement and unnamed portal.

Contrarily to synchronous clients, this client needs to store requests in the event loop while doing asynchronous I/O. The precise type for this storage needs to be provided by the user of this crate, and needs to implement both the Request and HandleRow traits.

This crate provides two API levels:

  • A higher-level one based using spawn_connection, which uses an existing event loop. This API requires an existing instance of Request+HandleRow.

  • A lower-level one based on the Connection type, which might be used to build more complex, or more direct pipelines, such as tunneling through another protocol, or waiting for a query to be executed by the server.

extern crate tokio;
extern crate pleingres;
extern crate futures;
extern crate env_logger;
extern crate uuid;

use uuid::Uuid;
use std::rc::Rc;
use std::net::ToSocketAddrs;
use futures::Future;

// A `Request` is the type used for communication with the
// client event loop. It is used both for sending input and
// receiving output.

struct Request {
    login: String,
    id: Option<Uuid>
}

// Requests must implement the `pleingres::Request` trait,
// meaning they can be converted to commands to be sent to
// the server.
impl pleingres::Request for Request {
    fn request(&mut self, mut buf: pleingres::Buffer) {
        buf.bind("SELECT id FROM users WHERE login=$1", &[&self.login]).execute(0);
    }
}

impl pleingres::HandleRow for Request {
    fn row(&mut self, mut row: pleingres::Row) -> bool {
        if let Some(id) = row.next() {
           self.id = Some(pleingres::FromSql::from_sql(id).unwrap())
        }
        true
    }
}

fn main() {
    env_logger::try_init().unwrap_or(());
    let p = Rc::new(pleingres::Parameters {
        addr: "::1:5432".to_socket_addrs().unwrap().next().unwrap(),
        user: "pe".to_string(),
        password: "password".to_string(),
        database: Some("pijul".to_string()),
        idle_timeout: Some(std::time::Duration::from_millis(20_000)),
        tcp_keepalive: Some(std::time::Duration::from_millis(10000)),
        ssl: None,
    });
    let mut l = tokio::reactor::Core::new().unwrap();

    let db:pleingres::Handle<Request> =
        pleingres::spawn_connection(p.clone(), l.handle()).unwrap();
    l.run(db
          .send_request(
            Request { login: "me".to_string(), id: None }
          )
          .and_then(|dbreq| {
              if let Some(ref id) = dbreq.id {
                  println!("id: {:?}", id)
              }
              futures::finished(())
          })).unwrap()
}

Alternatively, the pleingres::Request can be implemented using the sql plugin. On the above example, we would replace

This example is not tested
struct Request {
    login: String,
    id: Option<Uuid>
}

impl pleingres::Request for Request {
    fn request(&mut self, mut buf: pleingres::Buffer) {
        buf.bind("SELECT id FROM users WHERE login=$1", &[&self.login]).execute(0);
    }
}

With just

This example is not tested
#[sql("SELECT id FROM users WHERE login = $login")]
struct Request {
    login: String,
    id: Option<Uuid>
}

Re-exports

pub use pleingres_macros::HandleRowJoin;
pub use pleingres_macros::Request;
pub use pleingres_macros::sql;

Structs

Buffer

A single connection uses just two buffers, allocated at the beginning of the connection. This type is a view into one of these buffer, which can be used to send orders via the provided methods.

ConfigFile

A serializable version of Parameters, for inclusion in configuration files.

Connection

An active connection to a database.

Handle

A handle to a database connection that has been spawn to an event loop. This is actually a synchronization channel.

Parameters

Connection configuration: network address, user, database and options.

Portal

A portal (the result of a bind). Portals can be executed, or… executed.

Row

A result row, implementing an iterator on fields. Each field is a slice of bytes.

Rows

Result rows, returned by the query method of Connection.

SSLConfigFile
SSLParameters
SendRequest
SendRequestErr

A future ultimately resolving to a processed request.

ShutdownFuture
WriteFuture

Future resolving to the connection once a command has been sent to the server.

Enums

Error
FormatCode

SQL format code (text or binary).

PostgresError
RowResult

Result from a request.

SqlType

Postgres code for types.

Wait

A readiness signal sent by the server.

Traits

FromSql

Trait to produce types from their SQL representation.

HandleRow

Requests that can handle a resulting row.

Request

Types that can be converted to postgres commands.

Statement

Types representing statements.

SubRequest
SuperRequest
ToSql

Trait used to convert a type to its SQL representation.

Functions

spawn_connection

Setup a complete database connection. This is a high-level function combining the connection of a TcpStream, a postgres Connection, an initializer function (which can be used for instance to parse named statements) and a DatabaseConnection, and returning a handle into the spawned future.