From 2e8016d23c7a82d3809d2cd342c4c6008031babb Mon Sep 17 00:00:00 2001 From: Sam Samai Date: Sun, 12 Sep 2021 16:35:43 +1000 Subject: [PATCH] List posts with pagination --- examples/actix_example/.env | 2 + examples/actix_example/Cargo.toml | 1 + examples/actix_example/README.md | 7 ++ examples/actix_example/src/main.rs | 75 +++++++++++++------ .../actix_example/templates/index.html.tera | 10 ++- 5 files changed, 72 insertions(+), 23 deletions(-) diff --git a/examples/actix_example/.env b/examples/actix_example/.env index c22977ca..7389260b 100644 --- a/examples/actix_example/.env +++ b/examples/actix_example/.env @@ -1 +1,3 @@ +HOST=127.0.0.1 +PORT=5000 DATABASE_URL="mysql://root:@localhost/rocket_example" diff --git a/examples/actix_example/Cargo.toml b/examples/actix_example/Cargo.toml index 7b1692b3..454d20fa 100644 --- a/examples/actix_example/Cargo.toml +++ b/examples/actix_example/Cargo.toml @@ -17,6 +17,7 @@ actix-web = "3" actix-files = "0.5" tera = "1.8.0" dotenv = "0.15" +listenfd = "0.3.3" # remove `path = ""` in your own project sea-orm = { path = "../../", version = "^0.2", features = [ diff --git a/examples/actix_example/README.md b/examples/actix_example/README.md index a711113b..c289059c 100644 --- a/examples/actix_example/README.md +++ b/examples/actix_example/README.md @@ -1 +1,8 @@ # Actix with SeaORM example app + +Rus server with auto-reloading: + +```bash +cargo install systemfd +systemfd --no-pid -s http::5000 -- cargo watch -x run +``` diff --git a/examples/actix_example/src/main.rs b/examples/actix_example/src/main.rs index 0d46e044..5aadeb29 100644 --- a/examples/actix_example/src/main.rs +++ b/examples/actix_example/src/main.rs @@ -5,37 +5,56 @@ use actix_http::{body::Body, Response}; use actix_web::dev::ServiceResponse; use actix_web::http::StatusCode; use actix_web::middleware::errhandlers::{ErrorHandlerResponse, ErrorHandlers}; -use actix_web::{error, get, middleware, post, web, App, Error, HttpResponse, HttpServer, Result}; - +use actix_web::{ + error, get, middleware, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result, +}; +use listenfd::ListenFd; +use sea_orm::query::*; +use sea_orm::DatabaseConnection; +use sea_orm::EntityTrait; +use serde::Deserialize; +use std::env; use tera::Tera; mod post; pub use post::Entity as Post; -use sea_orm::query::*; -use sea_orm::DatabaseConnection; -use sea_orm::EntityTrait; - mod setup; +const DEFAULT_POSTS_PER_PAGE: usize = 4; + struct AppState { db_url: String, templates: tera::Tera, } +#[derive(Debug, Deserialize)] +pub struct Params { + page: Option, + posts_per_page: Option, +} + #[get("/")] -async fn list(data: web::Data) -> Result { +async fn list(req: HttpRequest, data: web::Data) -> Result { let template = &data.templates; let conn = sea_orm::Database::connect(&data.db_url).await.unwrap(); - let posts = Post::find() - .all(&conn) + // get params + let params = web::Query::::from_query(req.query_string()).unwrap(); + + let page = params.page.unwrap_or(0); + let posts_per_page = params.posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE); + let paginator = Post::find().paginate(&conn, posts_per_page); + let num_pages = paginator.num_pages().await.ok().unwrap(); + + let posts = paginator + .fetch_page(page) .await .expect("could not retrieve posts"); - let mut ctx = tera::Context::new(); ctx.insert("posts", &posts); - ctx.insert("page", &0); - ctx.insert("num_pages", &1); + ctx.insert("page", &page); + ctx.insert("posts_per_page", &posts_per_page); + ctx.insert("num_pages", &num_pages); let body = template .render("index.html.tera", &ctx) @@ -47,12 +66,20 @@ async fn list(data: web::Data) -> Result { async fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - let db_url = "mysql://root:@localhost/rocket_example"; + + // 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").expect("HOST is not set in .env file"); + let port = env::var("PORT").expect("PORT is not set in .env file"); + let server_url = format!("{}:{}", host, port); + + // create post table if not exists let conn = sea_orm::Database::connect(&db_url).await.unwrap(); let _ = setup::create_post_table(&conn).await; - println!("Listening on: 127.0.0.1:8080"); - HttpServer::new(move || { + let mut listenfd = ListenFd::from_env(); + let mut server = HttpServer::new(move || { let templates = Tera::new(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*")).unwrap(); App::new() .data(AppState { @@ -61,14 +88,20 @@ async fn main() -> std::io::Result<()> { }) .wrap(middleware::Logger::default()) // enable logger .service(fs::Files::new("/static", "./static").show_files_listing()) - .configure(init) // init todo routes - }) - .bind("127.0.0.1:8080")? - .run() - .await + .configure(init) + }); + + server = match listenfd.take_tcp_listener(0)? { + Some(listener) => server.listen(listener)?, + None => server.bind(&server_url)?, + }; + + println!("Starting server at {}", server_url); + server.run().await?; + + Ok(()) } -// function that will be called on new Application to configure routes for this module pub fn init(cfg: &mut web::ServiceConfig) { cfg.service(list); } diff --git a/examples/actix_example/templates/index.html.tera b/examples/actix_example/templates/index.html.tera index af741839..8737887c 100644 --- a/examples/actix_example/templates/index.html.tera +++ b/examples/actix_example/templates/index.html.tera @@ -48,9 +48,15 @@ {% if page == 0 %} Previous {% else %} - Previous + Previous {% endif %} | {% if page == num_pages - 1 %} Next {% else %} - Next + Next {% endif %}