From da178405b919c131c4b4865d15fafd73213ce28d Mon Sep 17 00:00:00 2001 From: Matt Paul Date: Wed, 18 Nov 2020 13:44:54 +0000 Subject: [PATCH] Copy 'todos' example directory as starting point --- examples/postgres/mockable-todos/Cargo.toml | 14 +++ examples/postgres/mockable-todos/README.md | 41 ++++++++ .../migrations/20200718111257_todos.sql | 6 ++ examples/postgres/mockable-todos/src/main.rs | 98 +++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 examples/postgres/mockable-todos/Cargo.toml create mode 100644 examples/postgres/mockable-todos/README.md create mode 100644 examples/postgres/mockable-todos/migrations/20200718111257_todos.sql create mode 100644 examples/postgres/mockable-todos/src/main.rs diff --git a/examples/postgres/mockable-todos/Cargo.toml b/examples/postgres/mockable-todos/Cargo.toml new file mode 100644 index 00000000..4295b6b0 --- /dev/null +++ b/examples/postgres/mockable-todos/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "sqlx-example-postgres-todos" +version = "0.1.0" +edition = "2018" +workspace = "../../../" + +[dependencies] +anyhow = "1.0" +async-std = { version = "1.4.0", features = [ "attributes" ] } +futures = "0.3" +paw = "1.0" +sqlx = { path = "../../../", features = ["postgres", "offline"] } +structopt = { version = "0.3", features = ["paw"] } +dotenv = "0.15.0" diff --git a/examples/postgres/mockable-todos/README.md b/examples/postgres/mockable-todos/README.md new file mode 100644 index 00000000..d28ae8b0 --- /dev/null +++ b/examples/postgres/mockable-todos/README.md @@ -0,0 +1,41 @@ +# TODOs Example + +## Setup + +1. Declare the database URL + + ``` + export DATABASE_URL="postgres://postgres:password@localhost/todos" + ``` + +2. Create the database. + + ``` + $ sqlx db create + ``` + +3. Run sql migrations + + ``` + $ sqlx migrate run + ``` + +## Usage + +Add a todo + +``` +cargo run -- add "todo description" +``` + +Complete a todo. + +``` +cargo run -- done +``` + +List all todos + +``` +cargo run +``` diff --git a/examples/postgres/mockable-todos/migrations/20200718111257_todos.sql b/examples/postgres/mockable-todos/migrations/20200718111257_todos.sql new file mode 100644 index 00000000..6599f8c1 --- /dev/null +++ b/examples/postgres/mockable-todos/migrations/20200718111257_todos.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS todos +( + id BIGSERIAL PRIMARY KEY, + description TEXT NOT NULL, + done BOOLEAN NOT NULL DEFAULT FALSE +); diff --git a/examples/postgres/mockable-todos/src/main.rs b/examples/postgres/mockable-todos/src/main.rs new file mode 100644 index 00000000..1fb38c5f --- /dev/null +++ b/examples/postgres/mockable-todos/src/main.rs @@ -0,0 +1,98 @@ +use sqlx::postgres::PgPool; +use sqlx::Done; +use std::env; +use structopt::StructOpt; + +#[derive(StructOpt)] +struct Args { + #[structopt(subcommand)] + cmd: Option, +} + +#[derive(StructOpt)] +enum Command { + Add { description: String }, + Done { id: i64 }, +} + +#[async_std::main] +#[paw::main] +async fn main(args: Args) -> anyhow::Result<()> { + let pool = PgPool::connect(&env::var("DATABASE_URL")?).await?; + + match args.cmd { + Some(Command::Add { description }) => { + println!("Adding new todo with description '{}'", &description); + let todo_id = add_todo(&pool, description).await?; + println!("Added new todo with id {}", todo_id); + } + Some(Command::Done { id }) => { + println!("Marking todo {} as done", id); + if complete_todo(&pool, id).await? { + println!("Todo {} is marked as done", id); + } else { + println!("Invalid id {}", id); + } + } + None => { + println!("Printing list of all todos"); + list_todos(&pool).await?; + } + } + + Ok(()) +} + +async fn add_todo(pool: &PgPool, description: String) -> anyhow::Result { + let rec = sqlx::query!( + r#" +INSERT INTO todos ( description ) +VALUES ( $1 ) +RETURNING id + "#, + description + ) + .fetch_one(pool) + .await?; + + Ok(rec.id) +} + +async fn complete_todo(pool: &PgPool, id: i64) -> anyhow::Result { + let rows_affected = sqlx::query!( + r#" +UPDATE todos +SET done = TRUE +WHERE id = $1 + "#, + id + ) + .execute(pool) + .await? + .rows_affected(); + + Ok(rows_affected > 0) +} + +async fn list_todos(pool: &PgPool) -> anyhow::Result<()> { + let recs = sqlx::query!( + r#" +SELECT id, description, done +FROM todos +ORDER BY id + "# + ) + .fetch_all(pool) + .await?; + + for rec in recs { + println!( + "- [{}] {}: {}", + if rec.done { "x" } else { " " }, + rec.id, + &rec.description, + ); + } + + Ok(()) +}