Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
X
committed
Sep 20, 2022
1 parent
bbeb861
commit 56e450c
Showing
23 changed files
with
1,475 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
HOST=127.0.0.1 | ||
PORT=8000 | ||
#DATABASE_URL="mysql://root:@localhost/poem_example" | ||
DATABASE_URL="sqlite::memory:" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.idea | ||
*.exe | ||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
[package] | ||
name = "sea-orm-salvo-example" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
[workspace] | ||
members = [".", "entity", "migration"] | ||
|
||
[dependencies] | ||
tokio = { version = "1.21.1", features = ["macros", "rt-multi-thread"] } | ||
salvo = { version = "0.35.1", features = ["affix", "serve-static"] } | ||
tracing = "0.1.36" | ||
tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } | ||
serde = { version = "1.0.144", features = ["derive"] } | ||
tera = "1.17.1" | ||
dotenv = "0.15" | ||
entity = { path = "entity" } | ||
migration = { path = "migration" } | ||
sea-orm = { version = "0.9.2", features = [ | ||
"debug-print", | ||
"runtime-tokio-native-tls", | ||
"sqlx-sqlite", | ||
# "sqlx-postgres", | ||
# "sqlx-mysql", | ||
] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
![screenshot](Screenshot.png) | ||
|
||
# Salvo with SeaORM example app | ||
|
||
[Modify from (github.com/SeaQL/sea-orm/examples/salvo_example](https://github.com/SeaQL/sea-orm/tree/master/examples/salvo_example)) | ||
|
||
1. Modify the `DATABASE_URL` var in `.env` to point to your chosen database | ||
|
||
2. Turn on the appropriate database feature for your chosen db in `Cargo.toml` (the `"sqlx-sqlite",` line) | ||
|
||
3. Execute `cargo run` to start the server | ||
|
||
4. Visit [localhost:8000](http://localhost:8000) in browser after seeing the `server started` line |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "entity" | ||
version = "0.1.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[lib] | ||
name = "entity" | ||
path = "src/lib.rs" | ||
|
||
[dependencies] | ||
serde = { version = "1", features = ["derive"] } | ||
sea-orm = "0.9.2" | ||
sea-orm-migration = "0.9.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod post; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
use sea_orm::entity::prelude::*; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Deserialize, Serialize)] | ||
#[sea_orm(table_name = "posts")] | ||
pub struct Model { | ||
#[sea_orm(primary_key)] | ||
#[serde(skip_deserializing)] | ||
pub id: i32, | ||
pub title: String, | ||
#[sea_orm(column_type = "Text")] | ||
pub text: String, | ||
} | ||
|
||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] | ||
pub enum Relation {} | ||
|
||
impl ActiveModelBehavior for ActiveModel {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "migration" | ||
version = "0.1.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[lib] | ||
name = "migration" | ||
path = "src/lib.rs" | ||
|
||
[dependencies] | ||
async-std = { version = "^1", features = ["attributes", "tokio1"] } | ||
sea-orm-migration = "0.9.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Running Migrator CLI | ||
|
||
- Apply all pending migrations | ||
```sh | ||
cargo run | ||
``` | ||
```sh | ||
cargo run -- up | ||
``` | ||
- Apply first 10 pending migrations | ||
```sh | ||
cargo run -- up -n 10 | ||
``` | ||
- Rollback last applied migrations | ||
```sh | ||
cargo run -- down | ||
``` | ||
- Rollback last 10 applied migrations | ||
```sh | ||
cargo run -- down -n 10 | ||
``` | ||
- Drop all tables from the database, then reapply all migrations | ||
```sh | ||
cargo run -- fresh | ||
``` | ||
- Rollback all applied migrations, then reapply all migrations | ||
```sh | ||
cargo run -- refresh | ||
``` | ||
- Rollback all applied migrations | ||
```sh | ||
cargo run -- reset | ||
``` | ||
- Check the status of all migrations | ||
```sh | ||
cargo run -- status | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
pub use sea_orm_migration::prelude::*; | ||
|
||
mod m20220120_000001_create_post_table; | ||
|
||
pub struct Migrator; | ||
|
||
#[async_trait::async_trait] | ||
impl MigratorTrait for Migrator { | ||
fn migrations() -> Vec<Box<dyn MigrationTrait>> { | ||
vec![Box::new(m20220120_000001_create_post_table::Migration)] | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
examples/seaorm/migration/src/m20220120_000001_create_post_table.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use sea_orm_migration::prelude::*; | ||
|
||
#[derive(DeriveMigrationName)] | ||
pub struct Migration; | ||
|
||
#[async_trait::async_trait] | ||
impl MigrationTrait for Migration { | ||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { | ||
manager | ||
.create_table( | ||
Table::create() | ||
.table(Posts::Table) | ||
.if_not_exists() | ||
.col( | ||
ColumnDef::new(Posts::Id) | ||
.integer() | ||
.not_null() | ||
.auto_increment() | ||
.primary_key(), | ||
) | ||
.col(ColumnDef::new(Posts::Title).string().not_null()) | ||
.col(ColumnDef::new(Posts::Text).string().not_null()) | ||
.to_owned(), | ||
) | ||
.await | ||
} | ||
|
||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { | ||
manager | ||
.drop_table(Table::drop().table(Posts::Table).to_owned()) | ||
.await | ||
} | ||
} | ||
|
||
/// Learn more at https://docs.rs/sea-query#iden | ||
#[derive(Iden)] | ||
enum Posts { | ||
Table, | ||
Id, | ||
Title, | ||
Text, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
use sea_orm_migration::prelude::*; | ||
|
||
#[async_std::main] | ||
async fn main() { | ||
cli::run_cli(migration::Migrator).await; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
use std::env; | ||
|
||
use entity::post; | ||
use migration::{Migrator, MigratorTrait}; | ||
use salvo::extra::affix; | ||
use salvo::extra::serve_static::StaticDir; | ||
use salvo::prelude::*; | ||
use salvo::writer::Text; | ||
use sea_orm::{entity::*, query::*, DatabaseConnection}; | ||
use tera::Tera; | ||
|
||
const DEFAULT_POSTS_PER_PAGE: u64 = 5; | ||
type Result<T> = std::result::Result<T, StatusError>; | ||
|
||
#[derive(Debug, Clone)] | ||
struct AppState { | ||
templates: tera::Tera, | ||
conn: DatabaseConnection, | ||
} | ||
|
||
#[handler] | ||
async fn create(req: &mut Request, depot: &mut Depot, res: &mut Response) -> Result<()> { | ||
let state = depot | ||
.obtain::<AppState>() | ||
.ok_or_else(StatusError::internal_server_error)?; | ||
let form = req | ||
.parse_form::<post::Model>() | ||
.await | ||
.map_err(|_| StatusError::bad_request())?; | ||
post::ActiveModel { | ||
title: Set(form.title.to_owned()), | ||
text: Set(form.text.to_owned()), | ||
..Default::default() | ||
} | ||
.save(&state.conn) | ||
.await | ||
.map_err(|_| StatusError::internal_server_error())?; | ||
|
||
res.render(Redirect::found("/").unwrap()); | ||
Ok(()) | ||
} | ||
|
||
#[handler] | ||
async fn list(req: &mut Request, depot: &mut Depot) -> Result<Text<String>> { | ||
let state = depot | ||
.obtain::<AppState>() | ||
.ok_or_else(StatusError::internal_server_error)?; | ||
let page = req.query("page").unwrap_or(1); | ||
let posts_per_page = req | ||
.query("posts_per_page") | ||
.unwrap_or(DEFAULT_POSTS_PER_PAGE) as usize; | ||
let paginator = post::Entity::find() | ||
.order_by_asc(post::Column::Id) | ||
.paginate(&state.conn, posts_per_page); | ||
let num_pages = paginator | ||
.num_pages() | ||
.await | ||
.map_err(|_| StatusError::bad_request())?; | ||
let posts = paginator | ||
.fetch_page(page - 1) | ||
.await | ||
.map_err(|_| StatusError::internal_server_error())?; | ||
|
||
let mut ctx = tera::Context::new(); | ||
ctx.insert("posts", &posts); | ||
ctx.insert("page", &page); | ||
ctx.insert("posts_per_page", &posts_per_page); | ||
ctx.insert("num_pages", &num_pages); | ||
|
||
let body = state | ||
.templates | ||
.render("index.html.tera", &ctx) | ||
.map_err(|_| StatusError::internal_server_error())?; | ||
Ok(Text::Html(body)) | ||
} | ||
|
||
#[handler] | ||
async fn new(depot: &mut Depot) -> Result<Text<String>> { | ||
let state = depot | ||
.obtain::<AppState>() | ||
.ok_or_else(StatusError::internal_server_error)?; | ||
let ctx = tera::Context::new(); | ||
let body = state | ||
.templates | ||
.render("new.html.tera", &ctx) | ||
.map_err(|_| StatusError::internal_server_error())?; | ||
Ok(Text::Html(body)) | ||
} | ||
|
||
#[handler] | ||
async fn edit(req: &mut Request, depot: &mut Depot) -> Result<Text<String>> { | ||
let state = depot | ||
.obtain::<AppState>() | ||
.ok_or_else(StatusError::internal_server_error)?; | ||
let id = req.param::<i32>("id").unwrap_or_default(); | ||
let post: post::Model = post::Entity::find_by_id(id) | ||
.one(&state.conn) | ||
.await | ||
.map_err(|_| StatusError::internal_server_error())? | ||
.ok_or_else(StatusError::not_found)?; | ||
|
||
let mut ctx = tera::Context::new(); | ||
ctx.insert("post", &post); | ||
|
||
let body = state | ||
.templates | ||
.render("edit.html.tera", &ctx) | ||
.map_err(|_| StatusError::internal_server_error())?; | ||
Ok(Text::Html(body)) | ||
} | ||
|
||
#[handler] | ||
async fn update(req: &mut Request, depot: &mut Depot, res: &mut Response) -> Result<()> { | ||
let state = depot | ||
.obtain::<AppState>() | ||
.ok_or_else(StatusError::internal_server_error)?; | ||
let id = req.param::<i32>("id").unwrap_or_default(); | ||
let form = req | ||
.parse_form::<post::Model>() | ||
.await | ||
.map_err(|_| StatusError::bad_request())?; | ||
post::ActiveModel { | ||
id: Set(id), | ||
title: Set(form.title.to_owned()), | ||
text: Set(form.text.to_owned()), | ||
} | ||
.save(&state.conn) | ||
.await | ||
.map_err(|_| StatusError::internal_server_error())?; | ||
res.render(Redirect::found("/").unwrap()); | ||
Ok(()) | ||
} | ||
|
||
#[handler] | ||
async fn delete(req: &mut Request, depot: &mut Depot, res: &mut Response) -> Result<()> { | ||
let state = depot | ||
.obtain::<AppState>() | ||
.ok_or_else(StatusError::internal_server_error)?; | ||
let id = req.param::<i32>("id").unwrap_or_default(); | ||
let post: post::ActiveModel = post::Entity::find_by_id(id) | ||
.one(&state.conn) | ||
.await | ||
.map_err(|_| StatusError::internal_server_error())? | ||
.ok_or_else(StatusError::not_found)? | ||
.into(); | ||
post.delete(&state.conn) | ||
.await | ||
.map_err(|_| StatusError::internal_server_error())?; | ||
|
||
res.render(Redirect::found("/").unwrap()); | ||
Ok(()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
std::env::set_var("RUST_LOG", "debug"); | ||
tracing_subscriber::fmt::init(); | ||
|
||
// get env vars | ||
dotenv::dotenv().ok(); | ||
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set in .env file"); | ||
let host = env::var("HOST").unwrap_or("0.0.0.0".to_owned()); | ||
let port = env::var("PORT").unwrap_or("8080".to_owned()); | ||
let server_url = format!("{}:{}", host, port); | ||
|
||
// create post table if not exists | ||
let conn = sea_orm::Database::connect(&db_url).await.unwrap(); | ||
Migrator::up(&conn, None).await.unwrap(); | ||
let templates = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap(); | ||
let state = AppState { templates, conn }; | ||
|
||
println!("Starting server at {}", server_url); | ||
|
||
let router = Router::new() | ||
.hoop(affix::inject(state)) | ||
.post(create) | ||
.get(list) | ||
.push(Router::with_path("new").get(new)) | ||
.push(Router::with_path("<id>").get(edit).post(update)) | ||
.push(Router::with_path("delete/<id>").post(delete)) | ||
.push(Router::with_path("static/<**>").get(StaticDir::new(concat!( | ||
env!("CARGO_MANIFEST_DIR"), | ||
"/static" | ||
)))); | ||
|
||
Server::new(TcpListener::bind(&server_url)) | ||
.serve(router) | ||
.await; | ||
} |
Oops, something went wrong.