Skip to content

Commit

Permalink
Merge pull request #222 from SeaQL/transaction-3
Browse files Browse the repository at this point in the history
Transaction 3
  • Loading branch information
tyt2y3 committed Oct 12, 2021
2 parents 213a3fb + 7bc6477 commit f58d890
Show file tree
Hide file tree
Showing 48 changed files with 2,801 additions and 348 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ jobs:
args: >
--all
- uses: actions-rs/cargo@v1
with:
command: test
args: >
--manifest-path sea-orm-rocket/Cargo.toml
cli:
name: CLI
runs-on: ${{ matrix.os }}
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ serde = { version = "^1.0", features = ["derive"] }
serde_json = { version = "^1", optional = true }
sqlx = { version = "^0.5", optional = true }
uuid = { version = "0.8", features = ["serde", "v4"], optional = true }
ouroboros = "0.11"

[dev-dependencies]
smol = { version = "^1.2" }
Expand Down
2 changes: 1 addition & 1 deletion examples/actix4_example/src/setup.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use sea_orm::sea_query::{ColumnDef, TableCreateStatement};
use sea_orm::{error::*, sea_query, DbConn, ExecResult};
use sea_orm::{error::*, sea_query, ConnectionTrait, DbConn, ExecResult};

async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result<ExecResult, DbErr> {
let builder = db.get_database_backend();
Expand Down
2 changes: 1 addition & 1 deletion examples/actix_example/src/setup.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use sea_orm::sea_query::{ColumnDef, TableCreateStatement};
use sea_orm::{error::*, sea_query, DbConn, ExecResult};
use sea_orm::{error::*, sea_query, ConnectionTrait, DbConn, ExecResult};

async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result<ExecResult, DbErr> {
let builder = db.get_database_backend();
Expand Down
17 changes: 12 additions & 5 deletions examples/rocket_example/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,22 @@ futures-util = { version = "^0.3" }
rocket = { git = "https://github.com/SergioBenitez/Rocket.git", features = [
"json",
] }
rocket_db_pools = { git = "https://github.com/SergioBenitez/Rocket.git" }
rocket_dyn_templates = { git = "https://github.com/SergioBenitez/Rocket.git", features = [
"tera",
] }
# remove `path = ""` in your own project
sea-orm = { path = "../../", version = "^0.2.3", features = ["macros"], default-features = false }
serde_json = { version = "^1" }

[dependencies.sea-orm]
path = "../../" # remove this line in your own project
version = "^0.2.3"
features = ["macros", "runtime-tokio-native-tls"]
default-features = false

[dependencies.sea-orm-rocket]
path = "../../sea-orm-rocket/lib" # remove this line in your own project and use the git line
# git = "https://github.com/SeaQL/sea-orm"

[features]
default = ["sqlx-postgres"]
sqlx-mysql = ["sea-orm/sqlx-mysql", "rocket_db_pools/sqlx_mysql"]
sqlx-postgres = ["sea-orm/sqlx-postgres", "rocket_db_pools/sqlx_postgres"]
sqlx-mysql = ["sea-orm/sqlx-mysql"]
sqlx-postgres = ["sea-orm/sqlx-postgres"]
2 changes: 1 addition & 1 deletion examples/rocket_example/Rocket.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[default]
template_dir = "templates/"

[default.databases.rocket_example]
[default.databases.sea_orm]
# Mysql
# make sure to enable "sqlx-mysql" feature in Cargo.toml, i.e default = ["sqlx-mysql"]
# url = "mysql://root:@localhost/rocket_example"
Expand Down
50 changes: 29 additions & 21 deletions examples/rocket_example/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@ use rocket::fs::{relative, FileServer};
use rocket::request::FlashMessage;
use rocket::response::{Flash, Redirect};
use rocket::{Build, Request, Rocket};
use rocket_db_pools::{sqlx, Connection, Database};
use rocket_dyn_templates::{context, Template};

use sea_orm::{entity::*, query::*};
use sea_orm_rocket::{Connection, Database};

mod pool;
use pool::RocketDbPool;
use pool::Db;

mod setup;

#[derive(Database, Debug)]
#[database("rocket_example")]
struct Db(RocketDbPool);

type Result<T, E = rocket::response::Debug<sqlx::Error>> = std::result::Result<T, E>;
type Result<T, E = rocket::response::Debug<sea_orm::DbErr>> = std::result::Result<T, E>;

mod post;
pub use post::Entity as Post;
Expand All @@ -34,25 +30,29 @@ async fn new() -> Template {
}

#[post("/", data = "<post_form>")]
async fn create(conn: Connection<Db>, post_form: Form<post::Model>) -> Flash<Redirect> {
async fn create(conn: Connection<'_, Db>, post_form: Form<post::Model>) -> Flash<Redirect> {
let db = conn.into_inner();

let form = post_form.into_inner();

post::ActiveModel {
title: Set(form.title.to_owned()),
text: Set(form.text.to_owned()),
..Default::default()
}
.save(&conn)
.save(db)
.await
.expect("could not insert post");

Flash::success(Redirect::to("/"), "Post successfully added.")
}

#[post("/<id>", data = "<post_form>")]
async fn update(conn: Connection<Db>, id: i32, post_form: Form<post::Model>) -> Flash<Redirect> {
async fn update(conn: Connection<'_, Db>, id: i32, post_form: Form<post::Model>) -> Flash<Redirect> {
let db = conn.into_inner();

let post: post::ActiveModel = Post::find_by_id(id)
.one(&conn)
.one(db)
.await
.unwrap()
.unwrap()
Expand All @@ -65,7 +65,7 @@ async fn update(conn: Connection<Db>, id: i32, post_form: Form<post::Model>) ->
title: Set(form.title.to_owned()),
text: Set(form.text.to_owned()),
}
.save(&conn)
.save(db)
.await
.expect("could not edit post");

Expand All @@ -74,11 +74,13 @@ async fn update(conn: Connection<Db>, id: i32, post_form: Form<post::Model>) ->

#[get("/?<page>&<posts_per_page>")]
async fn list(
conn: Connection<Db>,
conn: Connection<'_, Db>,
posts_per_page: Option<usize>,
page: Option<usize>,
flash: Option<FlashMessage<'_>>,
) -> Template {
let db = conn.into_inner();

// Set page number and items per page
let page = page.unwrap_or(1);
let posts_per_page = posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE);
Expand All @@ -89,7 +91,7 @@ async fn list(
// Setup paginator
let paginator = Post::find()
.order_by_asc(post::Column::Id)
.paginate(&conn, posts_per_page);
.paginate(db, posts_per_page);
let num_pages = paginator.num_pages().await.ok().unwrap();

// Fetch paginated posts
Expand All @@ -111,9 +113,11 @@ async fn list(
}

#[get("/<id>")]
async fn edit(conn: Connection<Db>, id: i32) -> Template {
async fn edit(conn: Connection<'_, Db>, id: i32) -> Template {
let db = conn.into_inner();

let post: Option<post::Model> = Post::find_by_id(id)
.one(&conn)
.one(db)
.await
.expect("could not find post");

Expand All @@ -126,22 +130,26 @@ async fn edit(conn: Connection<Db>, id: i32) -> Template {
}

#[delete("/<id>")]
async fn delete(conn: Connection<Db>, id: i32) -> Flash<Redirect> {
async fn delete(conn: Connection<'_, Db>, id: i32) -> Flash<Redirect> {
let db = conn.into_inner();

let post: post::ActiveModel = Post::find_by_id(id)
.one(&conn)
.one(db)
.await
.unwrap()
.unwrap()
.into();

post.delete(&conn).await.unwrap();
post.delete(db).await.unwrap();

Flash::success(Redirect::to("/"), "Post successfully deleted.")
}

#[delete("/")]
async fn destroy(conn: Connection<Db>) -> Result<()> {
Post::delete_many().exec(&conn).await.unwrap();
async fn destroy(conn: Connection<'_, Db>) -> Result<()> {
let db = conn.into_inner();

Post::delete_many().exec(db).await.unwrap();
Ok(())
}

Expand Down
20 changes: 11 additions & 9 deletions examples/rocket_example/src/pool.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use async_trait::async_trait;
use rocket_db_pools::{rocket::figment::Figment, Config};
use sea_orm_rocket::{rocket::figment::Figment, Config, Database};

#[derive(Debug)]
pub struct RocketDbPool {
#[derive(Database, Debug)]
#[database("sea_orm")]
pub struct Db(SeaOrmPool);

#[derive(Debug, Clone)]
pub struct SeaOrmPool {
pub conn: sea_orm::DatabaseConnection,
}

#[async_trait]
impl rocket_db_pools::Pool for RocketDbPool {
impl sea_orm_rocket::Pool for SeaOrmPool {
type Error = sea_orm::DbErr;

type Connection = sea_orm::DatabaseConnection;
Expand All @@ -16,12 +20,10 @@ impl rocket_db_pools::Pool for RocketDbPool {
let config = figment.extract::<Config>().unwrap();
let conn = sea_orm::Database::connect(&config.url).await.unwrap();

Ok(RocketDbPool {
conn,
})
Ok(SeaOrmPool { conn })
}

async fn get(&self) -> Result<Self::Connection, Self::Error> {
Ok(self.conn.clone())
fn borrow(&self) -> &Self::Connection {
&self.conn
}
}
2 changes: 1 addition & 1 deletion examples/rocket_example/src/setup.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use sea_orm::sea_query::{ColumnDef, TableCreateStatement};
use sea_orm::{error::*, sea_query, DbConn, ExecResult};
use sea_orm::{error::*, query::*, sea_query, DbConn, ExecResult};

async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result<ExecResult, DbErr> {
let builder = db.get_database_backend();
Expand Down
2 changes: 2 additions & 0 deletions sea-orm-rocket/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[workspace]
members = ["codegen", "lib"]
1 change: 1 addition & 0 deletions sea-orm-rocket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# SeaORM Rocket support crate.
22 changes: 22 additions & 0 deletions sea-orm-rocket/codegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "sea-orm-rocket-codegen"
version = "0.1.0-rc"
authors = ["Sergio Benitez <sb@sergio.bz>", "Jeb Rosen <jeb@jebrosen.com>"]
description = "Procedural macros for sea_orm_rocket."
repository = "https://github.com/SergioBenitez/Rocket/contrib/db_pools"
readme = "../README.md"
keywords = ["rocket", "framework", "database", "pools"]
license = "MIT OR Apache-2.0"
edition = "2018"

[lib]
proc-macro = true

[dependencies]
devise = "0.3"
quote = "1"

[dev-dependencies]
rocket = { git = "https://github.com/SergioBenitez/Rocket.git", default-features = false }
trybuild = "1.0"
version_check = "0.9"
110 changes: 110 additions & 0 deletions sea-orm-rocket/codegen/src/database.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use proc_macro::TokenStream;

use devise::{DeriveGenerator, FromMeta, MapperBuild, Support, ValidatorBuild};
use devise::proc_macro2_diagnostics::SpanDiagnosticExt;
use devise::syn::{self, spanned::Spanned};

const ONE_DATABASE_ATTR: &str = "missing `#[database(\"name\")]` attribute";
const ONE_UNNAMED_FIELD: &str = "struct must have exactly one unnamed field";

#[derive(Debug, FromMeta)]
struct DatabaseAttribute {
#[meta(naked)]
name: String,
}

pub fn derive_database(input: TokenStream) -> TokenStream {
DeriveGenerator::build_for(input, quote!(impl sea_orm_rocket::Database))
.support(Support::TupleStruct)
.validator(ValidatorBuild::new()
.struct_validate(|_, s| {
if s.fields.len() == 1 {
Ok(())
} else {
Err(s.span().error(ONE_UNNAMED_FIELD))
}
})
)
.outer_mapper(MapperBuild::new()
.struct_map(|_, s| {
let pool_type = match &s.fields {
syn::Fields::Unnamed(f) => &f.unnamed[0].ty,
_ => unreachable!("Support::TupleStruct"),
};

let decorated_type = &s.ident;
let db_ty = quote_spanned!(decorated_type.span() =>
<#decorated_type as sea_orm_rocket::Database>
);

quote_spanned! { decorated_type.span() =>
impl From<#pool_type> for #decorated_type {
fn from(pool: #pool_type) -> Self {
Self(pool)
}
}

impl std::ops::Deref for #decorated_type {
type Target = #pool_type;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl std::ops::DerefMut for #decorated_type {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

#[rocket::async_trait]
impl<'r> rocket::request::FromRequest<'r> for &'r #decorated_type {
type Error = ();

async fn from_request(
req: &'r rocket::request::Request<'_>
) -> rocket::request::Outcome<Self, Self::Error> {
match #db_ty::fetch(req.rocket()) {
Some(db) => rocket::outcome::Outcome::Success(db),
None => rocket::outcome::Outcome::Failure((
rocket::http::Status::InternalServerError, ()))
}
}
}

impl rocket::Sentinel for &#decorated_type {
fn abort(rocket: &rocket::Rocket<rocket::Ignite>) -> bool {
#db_ty::fetch(rocket).is_none()
}
}
}
})
)
.outer_mapper(quote!(#[rocket::async_trait]))
.inner_mapper(MapperBuild::new()
.try_struct_map(|_, s| {
let db_name = DatabaseAttribute::one_from_attrs("database", &s.attrs)?
.map(|attr| attr.name)
.ok_or_else(|| s.span().error(ONE_DATABASE_ATTR))?;

let fairing_name = format!("'{}' Database Pool", db_name);

let pool_type = match &s.fields {
syn::Fields::Unnamed(f) => &f.unnamed[0].ty,
_ => unreachable!("Support::TupleStruct"),
};

Ok(quote_spanned! { pool_type.span() =>
type Pool = #pool_type;

const NAME: &'static str = #db_name;

fn init() -> sea_orm_rocket::Initializer<Self> {
sea_orm_rocket::Initializer::with_name(#fairing_name)
}
})
})
)
.to_tokens()
}
Loading

0 comments on commit f58d890

Please sign in to comment.