WIP
This commit is contained in:
parent
53bbf32229
commit
73b72e3a31
Binary file not shown.
BIN
examples/rocket_example/db/sqlx/db.sqlite-shm
Normal file
BIN
examples/rocket_example/db/sqlx/db.sqlite-shm
Normal file
Binary file not shown.
0
examples/rocket_example/db/sqlx/db.sqlite-wal
Normal file
0
examples/rocket_example/db/sqlx/db.sqlite-wal
Normal file
@ -1,90 +0,0 @@
|
|||||||
use rocket::{Rocket, Build, futures};
|
|
||||||
use rocket::fairing::{self, AdHoc};
|
|
||||||
use rocket::response::status::Created;
|
|
||||||
use rocket::serde::{Serialize, Deserialize, json::Json};
|
|
||||||
|
|
||||||
use rocket_db_pools::{sqlx, Database, Connection};
|
|
||||||
|
|
||||||
use futures::{stream::TryStreamExt, future::TryFutureExt};
|
|
||||||
|
|
||||||
#[derive(Database)]
|
|
||||||
#[database("sqlx")]
|
|
||||||
struct Db(sqlx::SqlitePool);
|
|
||||||
|
|
||||||
type Result<T, E = rocket::response::Debug<sqlx::Error>> = std::result::Result<T, E>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
||||||
#[serde(crate = "rocket::serde")]
|
|
||||||
struct Post {
|
|
||||||
#[serde(skip_deserializing, skip_serializing_if = "Option::is_none")]
|
|
||||||
id: Option<i64>,
|
|
||||||
title: String,
|
|
||||||
text: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/", data = "<post>")]
|
|
||||||
async fn create(mut db: Connection<Db>, post: Json<Post>) -> Result<Created<Json<Post>>> {
|
|
||||||
// There is no support for `RETURNING`.
|
|
||||||
sqlx::query!("INSERT INTO posts (title, text) VALUES (?, ?)", post.title, post.text)
|
|
||||||
.execute(&mut *db)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Created::new("/").body(post))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
async fn list(mut db: Connection<Db>) -> Result<Json<Vec<i64>>> {
|
|
||||||
let ids = sqlx::query!("SELECT id FROM posts")
|
|
||||||
.fetch(&mut *db)
|
|
||||||
.map_ok(|record| record.id)
|
|
||||||
.try_collect::<Vec<_>>()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(ids))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/<id>")]
|
|
||||||
async fn read(mut db: Connection<Db>, id: i64) -> Option<Json<Post>> {
|
|
||||||
sqlx::query!("SELECT id, title, text FROM posts WHERE id = ?", id)
|
|
||||||
.fetch_one(&mut *db)
|
|
||||||
.map_ok(|r| Json(Post { id: Some(r.id), title: r.title, text: r.text }))
|
|
||||||
.await
|
|
||||||
.ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[delete("/<id>")]
|
|
||||||
async fn delete(mut db: Connection<Db>, id: i64) -> Result<Option<()>> {
|
|
||||||
let result = sqlx::query!("DELETE FROM posts WHERE id = ?", id)
|
|
||||||
.execute(&mut *db)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok((result.rows_affected() == 1).then(|| ()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[delete("/")]
|
|
||||||
async fn destroy(mut db: Connection<Db>) -> Result<()> {
|
|
||||||
sqlx::query!("DELETE FROM posts").execute(&mut *db).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
|
|
||||||
match Db::fetch(&rocket) {
|
|
||||||
Some(db) => match sqlx::migrate!("db/sqlx/migrations").run(&**db).await {
|
|
||||||
Ok(_) => Ok(rocket),
|
|
||||||
Err(e) => {
|
|
||||||
error!("Failed to initialize SQLx database: {}", e);
|
|
||||||
Err(rocket)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Err(rocket),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stage() -> AdHoc {
|
|
||||||
AdHoc::on_ignite("SQLx Stage", |rocket| async {
|
|
||||||
rocket.attach(Db::init())
|
|
||||||
.attach(AdHoc::try_on_ignite("SQLx Migrations", run_migrations))
|
|
||||||
.mount("/sqlx", routes![list, create, read, delete, destroy])
|
|
||||||
})
|
|
||||||
}
|
|
113
examples/rocket_example/src/sqlx/mod.rs
Normal file
113
examples/rocket_example/src/sqlx/mod.rs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
use rocket::fairing::{self, AdHoc};
|
||||||
|
use rocket::response::status::Created;
|
||||||
|
use rocket::serde::{json::Json, Deserialize, Serialize};
|
||||||
|
use rocket::{futures, Build, Rocket};
|
||||||
|
|
||||||
|
use rocket_db_pools::{sqlx, Connection, Database};
|
||||||
|
|
||||||
|
use futures::{future::TryFutureExt, stream::TryStreamExt};
|
||||||
|
|
||||||
|
// use post::*;
|
||||||
|
mod post;
|
||||||
|
pub use post::Entity as Post;
|
||||||
|
|
||||||
|
#[derive(Database)]
|
||||||
|
#[database("sqlx")]
|
||||||
|
struct Db(sqlx::SqlitePool);
|
||||||
|
|
||||||
|
type Result<T, E = rocket::response::Debug<sqlx::Error>> = std::result::Result<T, E>;
|
||||||
|
|
||||||
|
// #[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
// #[serde(crate = "rocket::serde")]
|
||||||
|
// struct Post {
|
||||||
|
// #[serde(skip_deserializing, skip_serializing_if = "Option::is_none")]
|
||||||
|
// id: Option<i64>,
|
||||||
|
// title: String,
|
||||||
|
// text: String,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[post("/", data = "<post>")]
|
||||||
|
// async fn create(mut db: Connection<Db>, post: Json<Post>) -> Result<Created<Json<Post>>> {
|
||||||
|
// // There is no support for `RETURNING`.
|
||||||
|
// sqlx::query!(
|
||||||
|
// "INSERT INTO posts (title, text) VALUES (?, ?)",
|
||||||
|
// post.title,
|
||||||
|
// post.text
|
||||||
|
// )
|
||||||
|
// .execute(&mut *db)
|
||||||
|
// .await?;
|
||||||
|
|
||||||
|
// Ok(Created::new("/").body(post))
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
async fn list(mut db: Connection<Db>) -> Result<Json<Vec<i64>>> {
|
||||||
|
// let ids = sqlx::query!("SELECT id FROM posts")
|
||||||
|
// .fetch(&mut *db)
|
||||||
|
// .map_ok(|record| record.id)
|
||||||
|
// .try_collect::<Vec<_>>()
|
||||||
|
// .await?;
|
||||||
|
let ids = vec![];
|
||||||
|
Ok(Json(ids))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/<id>")]
|
||||||
|
async fn read(mut db: Connection<Db>, id: i64) -> Option<Json<Post>> {
|
||||||
|
let post: Option<post::Model> = Post::find_by_id(id)
|
||||||
|
.one(db)
|
||||||
|
.await
|
||||||
|
.expect("could not find baker");
|
||||||
|
println!("post: {:#?}", post);
|
||||||
|
|
||||||
|
// sqlx::query!("SELECT id, title, text FROM posts WHERE id = ?", id)
|
||||||
|
// .fetch_one(&mut *db)
|
||||||
|
// .map_ok(|r| {
|
||||||
|
// Json(Post {
|
||||||
|
// id: Some(r.id),
|
||||||
|
// title: r.title,
|
||||||
|
// text: r.text,
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// .await
|
||||||
|
// .ok()
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[delete("/<id>")]
|
||||||
|
// async fn delete(mut db: Connection<Db>, id: i64) -> Result<Option<()>> {
|
||||||
|
// let result = sqlx::query!("DELETE FROM posts WHERE id = ?", id)
|
||||||
|
// .execute(&mut *db)
|
||||||
|
// .await?;
|
||||||
|
|
||||||
|
// Ok((result.rows_affected() == 1).then(|| ()))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[delete("/")]
|
||||||
|
// async fn destroy(mut db: Connection<Db>) -> Result<()> {
|
||||||
|
// sqlx::query!("DELETE FROM posts").execute(&mut *db).await?;
|
||||||
|
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
|
||||||
|
async fn run_migrations(rocket: Rocket<Build>) -> fairing::Result {
|
||||||
|
match Db::fetch(&rocket) {
|
||||||
|
Some(db) => match sqlx::migrate!("db/sqlx/migrations").run(&**db).await {
|
||||||
|
Ok(_) => Ok(rocket),
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to initialize SQLx database: {}", e);
|
||||||
|
Err(rocket)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => Err(rocket),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stage() -> AdHoc {
|
||||||
|
AdHoc::on_ignite("SQLx Stage", |rocket| async {
|
||||||
|
rocket
|
||||||
|
.attach(Db::init())
|
||||||
|
.attach(AdHoc::try_on_ignite("SQLx Migrations", run_migrations))
|
||||||
|
.mount("/sqlx", routes![list, read])
|
||||||
|
})
|
||||||
|
}
|
51
examples/rocket_example/src/sqlx/post.rs
Normal file
51
examples/rocket_example/src/sqlx/post.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
use rocket::serde::{json::Json, Deserialize, Serialize};
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
pub struct Entity;
|
||||||
|
|
||||||
|
impl EntityName for Entity {
|
||||||
|
fn table_name(&self) -> &str {
|
||||||
|
"post"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Deserialize, Serialize)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct Model {
|
||||||
|
pub id: Option<i64>,
|
||||||
|
pub title: String,
|
||||||
|
pub text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
|
pub enum Column {
|
||||||
|
Id,
|
||||||
|
Title,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||||
|
pub enum PrimaryKey {
|
||||||
|
Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimaryKeyTrait for PrimaryKey {
|
||||||
|
fn auto_increment() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColumnTrait for Column {
|
||||||
|
type EntityName = Entity;
|
||||||
|
|
||||||
|
fn def(&self) -> ColumnDef {
|
||||||
|
match self {
|
||||||
|
Self::Id => ColumnType::Integer.def(),
|
||||||
|
Self::Title => ColumnType::String(None).def(),
|
||||||
|
Self::Text => ColumnType::String(None).def(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
@ -1,7 +1,7 @@
|
|||||||
use rocket::fairing::AdHoc;
|
use rocket::fairing::AdHoc;
|
||||||
use rocket::local::blocking::Client;
|
|
||||||
use rocket::serde::{Serialize, Deserialize};
|
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
|
use rocket::local::blocking::Client;
|
||||||
|
use rocket::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
#[serde(crate = "rocket::serde")]
|
#[serde(crate = "rocket::serde")]
|
||||||
@ -20,13 +20,19 @@ fn test(base: &str, stage: AdHoc) {
|
|||||||
|
|
||||||
// Clear everything from the database.
|
// Clear everything from the database.
|
||||||
assert_eq!(client.delete(base).dispatch().status(), Status::Ok);
|
assert_eq!(client.delete(base).dispatch().status(), Status::Ok);
|
||||||
assert_eq!(client.get(base).dispatch().into_json::<Vec<i64>>(), Some(vec![]));
|
assert_eq!(
|
||||||
|
client.get(base).dispatch().into_json::<Vec<i64>>(),
|
||||||
|
Some(vec![])
|
||||||
|
);
|
||||||
|
|
||||||
// Add some random posts, ensure they're listable and readable.
|
// Add some random posts, ensure they're listable and readable.
|
||||||
for i in 1..=N{
|
for i in 1..=N {
|
||||||
let title = format!("My Post - {}", i);
|
let title = format!("My Post - {}", i);
|
||||||
let text = format!("Once upon a time, at {}'o clock...", i);
|
let text = format!("Once upon a time, at {}'o clock...", i);
|
||||||
let post = Post { title: title.clone(), text: text.clone() };
|
let post = Post {
|
||||||
|
title: title.clone(),
|
||||||
|
text: text.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
// Create a new post.
|
// Create a new post.
|
||||||
let response = client.post(base).json(&post).dispatch().into_json::<Post>();
|
let response = client.post(base).json(&post).dispatch().into_json::<Post>();
|
||||||
@ -66,13 +72,3 @@ fn test(base: &str, stage: AdHoc) {
|
|||||||
fn test_sqlx() {
|
fn test_sqlx() {
|
||||||
test("/sqlx", crate::sqlx::stage())
|
test("/sqlx", crate::sqlx::stage())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_diesel() {
|
|
||||||
test("/diesel", crate::diesel_sqlite::stage())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rusqlite() {
|
|
||||||
test("/rusqlite", crate::rusqlite::stage())
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user