From c6480635c05745121b58856b82e200cb2c51ee7f Mon Sep 17 00:00:00 2001 From: Sam Samai Date: Sat, 21 Aug 2021 21:58:20 +1000 Subject: [PATCH] WIP --- examples/rocket_example/Cargo.toml | 17 ++- examples/rocket_example/Rocket.toml | 7 +- examples/rocket_example/src/sqlx/mod.rs | 178 ++++++++++++++++++---- examples/rocket_example/src/sqlx/post.rs | 12 +- examples/rocket_example/src/sqlx/setup.rs | 37 +++++ examples/rocket_example/src/tests.rs | 74 --------- 6 files changed, 216 insertions(+), 109 deletions(-) create mode 100644 examples/rocket_example/src/sqlx/setup.rs delete mode 100644 examples/rocket_example/src/tests.rs diff --git a/examples/rocket_example/Cargo.toml b/examples/rocket_example/Cargo.toml index 44080a96..b53c613b 100644 --- a/examples/rocket_example/Cargo.toml +++ b/examples/rocket_example/Cargo.toml @@ -5,15 +5,17 @@ edition = "2018" publish = false [workspace] [dependencies] -# rocket = { path = "../../../Rocket/core/lib", features = ["json"] } -rocket = { git = "https://github.com/SergioBenitez/Rocket.git", branch = "master", features = [ - "json", -] } +rocket = { path = "../../../Rocket/core/lib", features = ["json"] } +# rocket = { git = "https://github.com/SergioBenitez/Rocket.git", branch = "master", features = [ +# "json", +# ] } # async-std = { version = "^1.9", features = ["attributes"] } sea-orm = { path = "../../", features = [ "sqlx-all", # "runtime-async-std-native-tls", ] } +sea-query = { version = "^0.12.8" } + serde_json = { version = "^1" } futures = { version = "^0.3" } async-stream = { version = "^0.3" } @@ -24,7 +26,10 @@ version = "0.5.1" default-features = false features = ["macros", "offline", "migrate"] +# [dependencies.rocket_db_pools] +# git = "https://github.com/SergioBenitez/Rocket" +# branch = "master" +# features = ["sea_orm"] [dependencies.rocket_db_pools] -git = "https://github.com/SergioBenitez/Rocket" -branch = "master" +path = "../../../Rocket/contrib/db_pools/lib" features = ["sqlx_sqlite"] diff --git a/examples/rocket_example/Rocket.toml b/examples/rocket_example/Rocket.toml index 300e46d3..0fe9f8eb 100644 --- a/examples/rocket_example/Rocket.toml +++ b/examples/rocket_example/Rocket.toml @@ -1,2 +1,5 @@ -[default.databases.sqlx] -url = "db/sqlx/db.sqlite" +# [default.databases.sqlx] +# url = "sqlite::memory:" + +[global.databases] +blog = { url = "sqlite::memory:" } diff --git a/examples/rocket_example/src/sqlx/mod.rs b/examples/rocket_example/src/sqlx/mod.rs index 178bb3ef..aec71324 100644 --- a/examples/rocket_example/src/sqlx/mod.rs +++ b/examples/rocket_example/src/sqlx/mod.rs @@ -6,17 +6,21 @@ use rocket::{futures, Build, Rocket}; use rocket_db_pools::{sqlx, Connection, Database}; use futures::{future::TryFutureExt, stream::TryStreamExt}; +use sea_orm::entity::*; +use sea_orm::QueryFilter; + +mod setup; + +#[derive(Database, Debug)] +#[database("blog")] +struct Db(rocket_db_pools::sqlx::SqlitePool); + +type Result> = std::result::Result; // use post::*; mod post; pub use post::Entity as Post; - -#[derive(Database)] -#[database("sqlx")] -struct Db(sqlx::SqlitePool); - -type Result> = std::result::Result; - +use sea_orm::DatabaseConnection; // #[derive(Debug, Clone, Deserialize, Serialize)] // #[serde(crate = "rocket::serde")] // struct Post { @@ -47,17 +51,58 @@ async fn list(mut db: Connection) -> Result>> { // .map_ok(|record| record.id) // .try_collect::>() // .await?; - let ids = vec![]; + // // let ids: Vec = vec![]; + + // let ids = sqlx::query( + // r#" + // SELECT id FROM posts + // "#, + // ) + // .execute(&mut *db) + // .await?; + // // .map_ok(|record| record.id); + // // .try_collect::>(); + // println!("ids: {:#?}", ids); + + // let ids: Vec = vec![]; + // Ok(Json(ids)) + + // let mut conn = db.acquire().await?; + // println!("conn: {:#?}", conn); + + // let ids = sqlx::query("SELECT id FROM posts") + // .fetch(&mut *db) + // .map_ok(|record| record.id) + // .try_collect::>() + // .await?; + + // Ok(Json(ids)) + + // let recs = sqlx::query( + // r#" + // SELECT id FROM posts + // "#, + // ) + // .fetch_all(&mut *db) + // .await?; + // let ids: Vec = recs.into(); + + // println!("recs: {:#?}", ids); + + let posts = Post::find().all(&mut *db).await.unwrap(); + assert_eq!(posts.len(), 0); + + let ids: Vec = vec![]; Ok(Json(ids)) } #[get("/")] async fn read(mut db: Connection, id: i64) -> Option> { - let post: Option = Post::find_by_id(id) - .one(db) - .await - .expect("could not find baker"); - println!("post: {:#?}", post); + // let post: Option = 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) @@ -90,24 +135,105 @@ async fn read(mut db: Connection, id: i64) -> Option> { // Ok(()) // } -async fn run_migrations(rocket: Rocket) -> 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), - } -} +// async fn run_migrations(rocket: Rocket) -> fairing::Result { +// use crate::rocket_db_pools::Pool; +// // 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), +// // } +// // let conn = Db::get(&rocket).await.expect("database connection"); + +// match Db::fetch(&rocket) { +// Some(db) => match setup::create_post_table(db.get().await().expect("database connection")).await { +// Ok(_) => { +// println!("rocket: {:#?}", rocket); + +// Ok(rocket) +// } +// Err(e) => { +// error!("Failed to initialize SQLx database: {}", e); +// Err(rocket) +// } +// }, +// None => Err(rocket), +// } +// // Ok(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)) + .attach(AdHoc::try_on_ignite("Create init post", |rocket| async { + let db = Db::fetch(&rocket).expect("database mounted"); + let res = sqlx::query( + r#" + CREATE TABLE posts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + title VARCHAR NOT NULL, + text VARCHAR NOT NULL, + published BOOLEAN NOT NULL DEFAULT 0 + )"#, + ) + .execute(&**db) + .await; + println!("res: {:#?}", res); + + let res2 = sqlx::query( + r#" + INSERT INTO posts (title, text) VALUES ('a post', 'content of a post') + "#, + ) + .execute(&**db) + .await; + println!("res2: {:#?}", res2); + + // Db::fetch(&rocket) + // .run(|db| { + // sqlx::query("DELETE FROM table").execute(&pool).await; + + // // conn.execute( + // // r#" + // // CREATE TABLE posts ( + // // id INTEGER PRIMARY KEY AUTOINCREMENT, + // // title VARCHAR NOT NULL, + // // text VARCHAR NOT NULL, + // // published BOOLEAN NOT NULL DEFAULT 0 + // // )"#, + // // params![], + // // ) + // }) + // .await + // .expect("can init rusqlite DB"); + Ok(rocket) + + // match Db::fetch(&rocket) { + // Some(db) => { + // println!("db: {:#?}", db); + // println!("&**db: {:#?}", &**db); + + // Ok(rocket) + // } + // None => Err(rocket), + // } + })) .mount("/sqlx", routes![list, read]) }) } + +// pub async fn create_post(db: &DbConn) { +// let post = post::ActiveModel { +// title: Set("Post One".to_owned()), +// text: Set("post content 1".to_owned()), +// ..Default::default() +// } +// .save(db) +// .await +// .expect("could not insert post"); +// } diff --git a/examples/rocket_example/src/sqlx/post.rs b/examples/rocket_example/src/sqlx/post.rs index 360792e1..96f694ac 100644 --- a/examples/rocket_example/src/sqlx/post.rs +++ b/examples/rocket_example/src/sqlx/post.rs @@ -1,7 +1,8 @@ use rocket::serde::{json::Json, Deserialize, Serialize}; use sea_orm::entity::prelude::*; -#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +#[derive(Copy, Clone, Default, Debug, DeriveEntity, Deserialize, Serialize)] +#[serde(crate = "rocket::serde")] pub struct Entity; impl EntityName for Entity { @@ -13,6 +14,7 @@ impl EntityName for Entity { #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Deserialize, Serialize)] #[serde(crate = "rocket::serde")] pub struct Model { + #[serde(skip_deserializing, skip_serializing_if = "Option::is_none")] pub id: Option, pub title: String, pub text: String, @@ -36,6 +38,9 @@ impl PrimaryKeyTrait for PrimaryKey { } } +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation {} + impl ColumnTrait for Column { type EntityName = Entity; @@ -48,4 +53,9 @@ impl ColumnTrait for Column { } } +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + panic!() + } +} impl ActiveModelBehavior for ActiveModel {} diff --git a/examples/rocket_example/src/sqlx/setup.rs b/examples/rocket_example/src/sqlx/setup.rs new file mode 100644 index 00000000..fb4882a5 --- /dev/null +++ b/examples/rocket_example/src/sqlx/setup.rs @@ -0,0 +1,37 @@ +use sea_orm::{error::*, sea_query, DbConn, ExecResult}; + +use sea_query::{ColumnDef, ForeignKey, ForeignKeyAction, Index, TableCreateStatement}; + +// mod post; +pub use super::post::*; + +async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result { + let builder = db.get_database_backend(); + db.execute(builder.build(stmt)).await +} + +pub async fn create_post_table(db: &DbConn) -> Result { + let stmt = sea_query::Table::create() + .table(super::post::Entity) + .if_not_exists() + .col( + ColumnDef::new(super::post::Column::Id) + .integer() + .not_null() + .auto_increment() + .primary_key(), + ) + .col( + ColumnDef::new(super::post::Column::Title) + .string() + .not_null(), + ) + .col( + ColumnDef::new(super::post::Column::Text) + .string() + .not_null(), + ) + .to_owned(); + + create_table(db, &stmt).await +} diff --git a/examples/rocket_example/src/tests.rs b/examples/rocket_example/src/tests.rs deleted file mode 100644 index 6d88b1c0..00000000 --- a/examples/rocket_example/src/tests.rs +++ /dev/null @@ -1,74 +0,0 @@ -use rocket::fairing::AdHoc; -use rocket::http::Status; -use rocket::local::blocking::Client; -use rocket::serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -#[serde(crate = "rocket::serde")] -struct Post { - title: String, - text: String, -} - -fn test(base: &str, stage: AdHoc) { - // Number of posts we're going to create/read/delete. - const N: usize = 20; - - // NOTE: If we had more than one test running concurently that dispatches - // DB-accessing requests, we'd need transactions or to serialize all tests. - let client = Client::tracked(rocket::build().attach(stage)).unwrap(); - - // Clear everything from the database. - assert_eq!(client.delete(base).dispatch().status(), Status::Ok); - assert_eq!( - client.get(base).dispatch().into_json::>(), - Some(vec![]) - ); - - // Add some random posts, ensure they're listable and readable. - for i in 1..=N { - let title = format!("My Post - {}", i); - let text = format!("Once upon a time, at {}'o clock...", i); - let post = Post { - title: title.clone(), - text: text.clone(), - }; - - // Create a new post. - let response = client.post(base).json(&post).dispatch().into_json::(); - assert_eq!(response.unwrap(), post); - - // Ensure the index shows one more post. - let list = client.get(base).dispatch().into_json::>().unwrap(); - assert_eq!(list.len(), i); - - // The last in the index is the new one; ensure contents match. - let last = list.last().unwrap(); - let response = client.get(format!("{}/{}", base, last)).dispatch(); - assert_eq!(response.into_json::().unwrap(), post); - } - - // Now delete all of the posts. - for _ in 1..=N { - // Get a valid ID from the index. - let list = client.get(base).dispatch().into_json::>().unwrap(); - let id = list.get(0).expect("have post"); - - // Delete that post. - let response = client.delete(format!("{}/{}", base, id)).dispatch(); - assert_eq!(response.status(), Status::Ok); - } - - // Ensure they're all gone. - let list = client.get(base).dispatch().into_json::>().unwrap(); - assert!(list.is_empty()); - - // Trying to delete should now 404. - let response = client.delete(format!("{}/{}", base, 1)).dispatch(); - assert_eq!(response.status(), Status::NotFound); -} - -#[test] -fn test_sqlx() { - test("/sqlx", crate::sqlx::stage()) -}