Clone TODOs example for SQLite

Differences to Postgres version:
- Minor changes to schema
- Add TODO: "RETURNING" isn't supported, so retrieve ID separately
This commit is contained in:
Jon Pacheco 2020-03-31 12:35:51 +01:00
parent 283f0ef6d8
commit 79a5e5e1d5
6 changed files with 161 additions and 0 deletions

12
Cargo.lock generated
View File

@ -1765,6 +1765,18 @@ dependencies = [
"structopt",
]
[[package]]
name = "sqlx-example-sqlite-todos"
version = "0.1.0"
dependencies = [
"anyhow",
"async-std",
"futures 0.3.4",
"paw",
"sqlx",
"structopt",
]
[[package]]
name = "sqlx-macros"
version = "0.3.2"

View File

@ -7,6 +7,7 @@ members = [
"examples/postgres/listen",
"examples/postgres/realworld",
"examples/postgres/todos",
"examples/sqlite/todos",
]
[package]

View File

@ -0,0 +1,13 @@
[package]
name = "sqlx-example-sqlite-todos"
version = "0.1.0"
edition = "2018"
workspace = "../../../"
[dependencies]
anyhow = "1.0"
async-std = { version = "1.5.0", features = [ "attributes" ] }
futures = "0.3"
paw = "1.0"
sqlx = { path = "../../../", features = ["sqlite"] }
structopt = { version = "0.3", features = ["paw"] }

View File

@ -0,0 +1,27 @@
# TODOs Example
## Usage
Declare the database URL:
```
export DATABASE_URL="sqlite:///path/to/this/directory/todos.db"
```
Create the database:
```
sqlite3 todos.db
```
Load the database schema (using the SQLite CLI interface opened from the previous command):
```
sqlite> .read schema.sql
```
Use `.exit` to leave the SQLite CLI. Then, to run this example:
- Add a todo: `cargo run -- add "todo description"`
- Complete a todo: `cargo run -- done <todo id>`
- List all todos: `cargo run`

View File

@ -0,0 +1,5 @@
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY NOT NULL,
description TEXT NOT NULL,
done BOOLEAN NOT NULL DEFAULT 0
);

View File

@ -0,0 +1,103 @@
use sqlx::SqlitePool;
use sqlx::sqlite::SqliteQueryAs;
use std::env;
use structopt::StructOpt;
#[derive(StructOpt)]
struct Args {
#[structopt(subcommand)]
cmd: Option<Command>,
}
#[derive(StructOpt)]
enum Command {
Add { description: String },
Done { id: i64 },
}
#[async_std::main]
#[paw::main]
async fn main(args: Args) -> anyhow::Result<()> {
let pool = SqlitePool::new(&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: &SqlitePool, description: String) -> anyhow::Result<i64> {
// Insert the TODO, then obtain the ID of this row
sqlx::query!(
r#"
INSERT INTO todos ( description )
VALUES ( $1 )
"#,
description
)
.execute(pool)
.await?;
let rec: (i64,) = sqlx::query_as(
"SELECT last_insert_rowid()"
)
.fetch_one(pool)
.await?;
Ok(rec.0)
}
async fn complete_todo(pool: &SqlitePool, id: i64) -> anyhow::Result<bool> {
let rows_affected = sqlx::query!(
r#"
UPDATE todos
SET done = TRUE
WHERE id = $1
"#,
id
)
.execute(pool)
.await?;
Ok(rows_affected > 0)
}
async fn list_todos(pool: &SqlitePool) -> 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(())
}