diff --git a/Cargo.toml b/Cargo.toml index d4a2d904..18db9ddd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,9 @@ +[workspace] +members = [ + ".", + "examples/todo" +] + [package] name = "sqlx" version = "0.0.0" @@ -22,5 +28,4 @@ memchr = "2.2.1" runtime = { version = "=0.3.0-alpha.6", default-features = false } [dev-dependencies] -env_logger = "0.6.2" -runtime-tokio = { version = "=0.3.0-alpha.5" } +runtime = { version = "=0.3.0-alpha.6", default-features = true } diff --git a/examples/postgres.rs b/examples/postgres.rs deleted file mode 100644 index f25b4af4..00000000 --- a/examples/postgres.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![feature(async_await)] - -use futures::{future, TryStreamExt}; -use sqlx::{postgres::Connection, ConnectOptions}; -use std::{collections::HashMap, io}; - -// TODO: Connection strings ala postgres@localhost/sqlx_dev - -#[runtime::main(runtime_tokio::Tokio)] -async fn main() -> io::Result<()> { - env_logger::init(); - - let mut conn = Connection::establish( - ConnectOptions::new() - .host("127.0.0.1") - .port(5432) - .user("postgres") - .database("sqlx__dev"), - ) - .await?; - - println!(" :: create schema"); - - conn.prepare( - r#" -CREATE TABLE IF NOT EXISTS users ( - id BIGSERIAL PRIMARY KEY, - name TEXT NOT NULL, - password TEXT -); - "#, - ) - .execute() - .await?; - - println!(" :: insert"); - - let user_id: i64 = conn - .prepare("INSERT INTO users (name) VALUES ($1) RETURNING id") - .bind("Joe") - .get() - .await?; - - println!("insert {:?}", user_id); - - println!(" :: select"); - - // Iterate through each row, one-by-one - conn.prepare("SELECT id, name, password FROM users") - .select() - .try_for_each(|(id, name, password): (i64, String, Option)| { - println!("select {} -> {} (password = {:?})", id, name, password); - - future::ok(()) - }) - .await?; - - // Get a map of id -> name of users with a name of JOE - let map: HashMap = conn - .prepare("SELECT id, name FROM users WHERE name = $1") - .bind("Joe") - .select() - .try_collect() - .await?; - - println!(" :: users\n{:#?}\n", map); - - conn.close().await?; - - Ok(()) -} diff --git a/examples/todo/Cargo.toml b/examples/todo/Cargo.toml new file mode 100644 index 00000000..601398cb --- /dev/null +++ b/examples/todo/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "todo" +version = "0.1.0" +edition = "2018" + +[dependencies] +sqlx = { path = "../.." } +failure = "0.1.5" +env_logger = "0.6.2" +runtime = { version = "=0.3.0-alpha.6", default-features = false } +runtime-tokio = { version = "=0.3.0-alpha.5" } +futures-preview = "=0.3.0-alpha.17" +structopt = "0.2.18" diff --git a/examples/todo/src/main.rs b/examples/todo/src/main.rs new file mode 100644 index 00000000..0783f698 --- /dev/null +++ b/examples/todo/src/main.rs @@ -0,0 +1,131 @@ +#![feature(async_await)] + +use failure::Fallible; +use futures::{future, TryStreamExt}; +use sqlx::postgres::Connection; +use structopt::StructOpt; + +#[derive(StructOpt, Debug)] +struct Options { + #[structopt(subcommand)] + cmd: Option +} + +#[derive(StructOpt, Debug)] +enum Command { + #[structopt(name = "add")] + Add { + text: String, + }, + + #[structopt(name = "done")] + MarkAsDone { id: i64 } +} + +#[runtime::main(runtime_tokio::Tokio)] +async fn main() -> Fallible<()> { + env_logger::try_init()?; + + let opt = Options::from_args(); + + let mut conn = Connection::establish( + sqlx::ConnectOptions::new() + .host("127.0.0.1") + .port(5432) + .user("postgres") + .database("sqlx__dev__tasks"), + ) + .await?; + + ensure_schema(&mut conn).await?; + + match opt.cmd { + Some(Command::Add { text }) => { + add_task(&mut conn, &text).await?; + } + + Some(Command::MarkAsDone { id }) => { + mark_task_as_done(&mut conn, id).await?; + } + + None => { + print_all_tasks(&mut conn).await?; + } + } + + Ok(()) +} + +async fn ensure_schema(conn: &mut Connection) -> Fallible<()> { + conn.prepare("BEGIN").execute().await?; + + // language=sql + conn.prepare( + r#" +CREATE TABLE IF NOT EXISTS tasks ( + id BIGSERIAL PRIMARY KEY, + text TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + done_at TIMESTAMPTZ +) + "#, + ) + .execute() + .await?; + + conn.prepare("COMMIT").execute().await?; + + Ok(()) +} + +async fn print_all_tasks(conn: &mut Connection) -> Fallible<()> { + // language=sql + conn.prepare( + r#" +SELECT id, text +FROM tasks +WHERE done_at IS NULL + "#, + ) + .select() + .try_for_each(|(id, text): (i64, String)| { + // language=text + println!("{:>5} | {}", id, text); + + future::ok(()) + }) + .await?; + + Ok(()) +} + +async fn add_task(conn: &mut Connection, text: &str) -> Fallible<()> { + // language=sql + conn.prepare( + r#" +INSERT INTO tasks ( text ) +VALUES ( $1 ) + "#, + ) + .bind(text) + .execute() + .await?; + + Ok(()) +} + +async fn mark_task_as_done(conn: &mut Connection, id: i64) -> Fallible<()> { + // language=sql + conn.prepare( + r#" +UPDATE tasks +SET done_at = now() +WHERE id = $1 + "#, + ) + .bind(id) + .execute() + .await?; + + Ok(()) +}