mirror of https://github.com/rwf2/Rocket.git
Update 'databases' example README.
The README now more completely documents the example. All implementations now make use of 'RETURNING'.
This commit is contained in:
parent
aa7805a5f8
commit
fc76bf7b68
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "INSERT INTO posts (title, text) VALUES (?, ?)",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 2
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "3c289da9873097a11191dbedc5c78d86afd6a6d36771bfeb12f331abca6279cf"
|
|
||||||
}
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "INSERT INTO posts (title, text) VALUES (?, ?) RETURNING id",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Int64"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "bea4ef6e25064f6b383e854f8bc2770d89cfaf9859d0bfca78b2ca24627675b7"
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket = { path = "../../core/lib", features = ["json"] }
|
rocket = { path = "../../core/lib", features = ["json"] }
|
||||||
diesel = "2"
|
diesel = { version = "2", features = ["returning_clauses_for_sqlite_3_35"] }
|
||||||
diesel_migrations = "2"
|
diesel_migrations = "2"
|
||||||
|
|
||||||
[dependencies.sqlx]
|
[dependencies.sqlx]
|
||||||
|
|
|
@ -1,8 +1,69 @@
|
||||||
# Databases Example
|
# Databases Example
|
||||||
|
|
||||||
This example makes use of SQLite. You'll need `sqlite3` and its development
|
This example makes use of SQLite and MySQL. You'll need `sqlite3` and a MySQL
|
||||||
headers installed:
|
client installed:
|
||||||
|
|
||||||
* **macOS:** `brew install sqlite`
|
* **macOS:** `brew install sqlite mysql-client`
|
||||||
* **Debian**, **Ubuntu:** `apt-get install libsqlite3-dev`
|
* **Debian**, **Ubuntu:** `apt-get install libsqlite3-dev libmysqlclient-dev`
|
||||||
* **Arch:** `pacman -S sqlite`
|
* **Arch:** `pacman -S sqlite libmysqlclient`
|
||||||
|
|
||||||
|
## API Implementation
|
||||||
|
|
||||||
|
This example implements a JSON-based HTTP API for a "blog" using several database drivers:
|
||||||
|
|
||||||
|
* `sqlx` (`/sqlx`, `sqlx.rs`)
|
||||||
|
* `rusqlite` (`/rusqlite`, `rusqlite.rs`)
|
||||||
|
* `diesel` (sqlite) (`/diesel`, `diesel_sqlite.rs`)
|
||||||
|
* `diesel-async` (mysql) (`/diesel-async`, `diesel_mysql.rs`)
|
||||||
|
|
||||||
|
The exposed API is succinctly described as follows, with
|
||||||
|
[`httpie`](https://httpie.io/) CLI examples:
|
||||||
|
|
||||||
|
* `POST /driver`: create post via JSON with `title` and `text`; returns new
|
||||||
|
post JSON with new `id`
|
||||||
|
|
||||||
|
http http://127.0.0.1:8000/sqlx title="Title" text="Hello, world."
|
||||||
|
> { "id": 2128, "text": "Hello, world.", "title": "Title" }
|
||||||
|
|
||||||
|
* `GET /driver`: returns JSON array of IDs for blog posts
|
||||||
|
|
||||||
|
http http://127.0.0.1:8000/sqlx
|
||||||
|
> [ 2128, 2129, 2130, 2131 ]
|
||||||
|
|
||||||
|
* `GET /driver/<id>`: returns a JSON object for the post with id `<id>`
|
||||||
|
|
||||||
|
http http://127.0.0.1:8000/sqlx/2128
|
||||||
|
> { "id": 2128, "text": "Hello, world.", "title": "Title" }
|
||||||
|
|
||||||
|
* `DELETE /driver`: delete all posts
|
||||||
|
|
||||||
|
http delete http://127.0.0.1:8000/sqlx
|
||||||
|
|
||||||
|
* `DELETE /driver/<id>`: delete post with id `<id>`
|
||||||
|
|
||||||
|
http delete http://127.0.0.1:8000/sqlx/4
|
||||||
|
|
||||||
|
## Migrations
|
||||||
|
|
||||||
|
Database migrations are stored in the respective `db/${driver}` directory.
|
||||||
|
|
||||||
|
### `diesel`
|
||||||
|
|
||||||
|
Diesel migrations are found in `db/diesel/migrations`. They are run
|
||||||
|
automatically. They can be run manually as well:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install diesel_cli --no-default-features --features sqlite
|
||||||
|
DATABASE_URL="db/diesel/db.sqlite" diesel migration --migration-dir db/diesel/migrations redo
|
||||||
|
```
|
||||||
|
|
||||||
|
### `sqlx`
|
||||||
|
|
||||||
|
sqlx migrations are found in `db/sqlx/migrations`. They are run automatically.
|
||||||
|
|
||||||
|
Query metadata for offline checking was prepared with the following commands:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo install sqlx-cli --no-default-features --features sqlite
|
||||||
|
DATABASE_URL="sqlite:$(pwd)/db/sqlx/db.sqlite" cargo sqlx prepare
|
||||||
|
```
|
||||||
|
|
|
@ -92,6 +92,6 @@ async fn destroy(mut db: Connection<Db>) -> Result<()> {
|
||||||
pub fn stage() -> AdHoc {
|
pub fn stage() -> AdHoc {
|
||||||
AdHoc::on_ignite("Diesel SQLite Stage", |rocket| async {
|
AdHoc::on_ignite("Diesel SQLite Stage", |rocket| async {
|
||||||
rocket.attach(Db::init())
|
rocket.attach(Db::init())
|
||||||
.mount("/diesel-async/", routes![list, read, create, delete, destroy])
|
.mount("/diesel-async", routes![list, read, create, delete, destroy])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,14 +32,16 @@ table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/", data = "<post>")]
|
#[post("/", data = "<post>")]
|
||||||
async fn create(db: Db, post: Json<Post>) -> Result<Created<Json<Post>>> {
|
async fn create(db: Db, mut post: Json<Post>) -> Result<Created<Json<Post>>> {
|
||||||
let post_value = post.clone();
|
let post_value = post.clone();
|
||||||
db.run(move |conn| {
|
let id: Option<i32> = db.run(move |conn| {
|
||||||
diesel::insert_into(posts::table)
|
diesel::insert_into(posts::table)
|
||||||
.values(&*post_value)
|
.values(&*post_value)
|
||||||
.execute(conn)
|
.returning(posts::id)
|
||||||
|
.get_result(conn)
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
|
post.id = Some(id.expect("returning guarantees id present"));
|
||||||
Ok(Created::new("/").body(post))
|
Ok(Created::new("/").body(post))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,15 @@ struct Post {
|
||||||
type Result<T, E = Debug<rusqlite::Error>> = std::result::Result<T, E>;
|
type Result<T, E = Debug<rusqlite::Error>> = std::result::Result<T, E>;
|
||||||
|
|
||||||
#[post("/", data = "<post>")]
|
#[post("/", data = "<post>")]
|
||||||
async fn create(db: Db, post: Json<Post>) -> Result<Created<Json<Post>>> {
|
async fn create(db: Db, mut post: Json<Post>) -> Result<Created<Json<Post>>> {
|
||||||
let item = post.clone();
|
let item = post.clone();
|
||||||
db.run(move |conn| {
|
let id = db.run(move |conn| {
|
||||||
conn.execute("INSERT INTO posts (title, text) VALUES (?1, ?2)",
|
conn.query_row("INSERT INTO posts (title, text) VALUES (?1, ?2) RETURNING id",
|
||||||
params![item.title, item.text])
|
params![item.title, item.text],
|
||||||
|
|r| r.get(0))
|
||||||
}).await?;
|
}).await?;
|
||||||
|
|
||||||
|
post.id = Some(id);
|
||||||
Ok(Created::new("/").body(post))
|
Ok(Created::new("/").body(post))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,13 @@ struct Post {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/", data = "<post>")]
|
#[post("/", data = "<post>")]
|
||||||
async fn create(mut db: Connection<Db>, post: Json<Post>) -> Result<Created<Json<Post>>> {
|
async fn create(mut db: Connection<Db>, mut post: Json<Post>) -> Result<Created<Json<Post>>> {
|
||||||
// There is no support for `RETURNING`.
|
let query = sqlx::query! {
|
||||||
sqlx::query!("INSERT INTO posts (title, text) VALUES (?, ?)", post.title, post.text)
|
"INSERT INTO posts (title, text) VALUES (?, ?) RETURNING id",
|
||||||
.execute(&mut **db)
|
post.title, post.text
|
||||||
.await?;
|
};
|
||||||
|
|
||||||
|
post.id = Some(query.fetch_one(&mut **db).await?.id);
|
||||||
Ok(Created::new("/").body(post))
|
Ok(Created::new("/").body(post))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue