#postgresql #statement #request #portal #future #connection #user

pleingres

一个纯 Rust 的 PostgreSQL 接口。永远不会阻塞(因此得名,法语中的一个双关语)。

15 个版本

使用旧的 Rust 2015

0.4.5 2019 年 3 月 21 日
0.4.4 2019 年 3 月 21 日
0.4.2 2018 年 12 月 24 日
0.4.1 2018 年 7 月 14 日
0.1.2 2017 年 5 月 15 日

#1375数据库接口

24 每月下载量

Apache-2.0/MIT

110KB
2.5K SLoC

一个全异步的 Postgres 客户端。Postgres 有“语句”的概念,即命名或未命名的 SQL 命令,以及“门径”,其中门径是结果的一个实例。所有对数据库的查询都遵循相同的顺序:解析、绑定、执行、关闭(门径和/或语句)。

语句和门径可以是命名的或未命名的,尽管使用 Connection 类型的 query 方法编写原型代码可能更容易,该方法使用未命名的语句和未命名的门径来执行正确的顺序。

与同步客户端相反,此客户端需要在异步 I/O 时在事件循环中存储请求。此存储的确切类型需要由此 crate 的用户提供,并且需要实现 RequestHandleRow 特性。

此 crate 提供了两个 API 级别

  • 一个基于 spawn_connection 的高级 API,它使用现有的事件循环。此 API 需要现有的 Request+HandleRow 实例。

  • 一个基于 Connection 类型的低级 API,可能用于构建更复杂或更直接的流水线,例如通过另一个协议隧道,或等待服务器执行查询。

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()
}

或者,可以使用 sql 插件实现 pleingres::Request。在上面的例子中,我们会用以下替换

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);
    }
}

只需

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

依赖项

~12MB
~211K SLoC