Skip to content

Instantly share code, notes, and snippets.

@abalmos
Created November 20, 2019 20:29
Show Gist options
  • Save abalmos/5c365869ab58c3268143ed84e4405ee6 to your computer and use it in GitHub Desktop.
Save abalmos/5c365869ab58c3268143ed84e4405ee6 to your computer and use it in GitHub Desktop.
Using tokio-postgres with async-std runtime
[package]
name = "async-std-tokio-postgres"
version = "0.1.0"
authors = ["Andrew Balmos <andrew@balmos.org>"]
edition = "2018"
[dependencies]
tokio-postgres = { version = "0.5.0-alpha.1", default-features = false }
futures = "0.3.1"
futures-util = "0.4.1"
async-std = { version = "1.0.1", features = [ "attributes" ] }
tokio-io = "0.2.0-alpha.6"
mod tokio_compat;
use tokio_compat::TokioCompatExt;
use tokio_postgres::tls::NoTls;
use tokio_postgres::{Config, Row};
use async_std::task;
use async_std::net::TcpStream;
use futures_util::future::FutureExt;
impl TokioCompatExt for TcpStream {}
// impl TokioCompatExt for UnixStream {} // Also works
#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note: You must connect to the server yourself to use `async-std` TcpStream
let stream = TcpStream::connect("localhost:5432").await?.compat();
let config = "user=postgres password=postgres";
let config = config.parse::<Config>()?;
// Connect to the database.
let (client, connection) = config.connect_raw(stream, NoTls).await?;
// The connection object performs the actual communication with the database,
// so spawn it off to run on its own.
let connection = connection.map(|r| {
if let Err(e) = r {
eprintln!("connection error: {}", e);
}
});
task::spawn(connection);
// Now we can prepare a simple statement that just returns its parameter.
let stmt = client.prepare("SELECT $1::TEXT").await?;
// And then execute it, returning a Stream of Rows which we collect into a Vec.
let rows: Vec<Row> = client
.query(&stmt, &[&"hello world"])
.await?;
// Now we can check that we got back the same string we sent over.
let value: &str = rows[0].get(0);
assert_eq!(value, "hello world");
Ok(())
}
// reference: https://github.com/jedisct1/rust-async-std-tokio-compat
use futures::io::{AsyncRead, AsyncWrite};
use std::pin::Pin;
use std::task::{Context, Poll};
pub struct TokioCompat<T>(T);
pub trait TokioCompatExt: AsyncRead + AsyncWrite + Sized {
#[inline]
fn compat(self) -> TokioCompat<Self> {
TokioCompat(self)
}
}
impl<T: AsyncRead + Unpin> tokio_io::AsyncRead for TokioCompat<T> {
#[inline]
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context,
buf: &mut [u8],
) -> Poll<Result<usize, std::io::Error>> {
Pin::new(&mut self.0).poll_read(cx, buf)
}
}
impl<T: AsyncWrite + Unpin> tokio_io::AsyncWrite for TokioCompat<T> {
#[inline]
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context,
buf: &[u8],
) -> Poll<Result<usize, std::io::Error>> {
Pin::new(&mut self.0).poll_write(cx, buf)
}
#[inline]
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), std::io::Error>> {
Pin::new(&mut self.0).poll_flush(cx)
}
#[inline]
fn poll_shutdown(
mut self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll<Result<(), std::io::Error>> {
Pin::new(&mut self.0).poll_close(cx)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment