From 2f597030b5c08324efd92e4ba27580c1cc7f083f Mon Sep 17 00:00:00 2001 From: candifloss Date: Wed, 22 Apr 2026 14:35:44 +0530 Subject: [PATCH] Sample layout with test data --- src/db.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 37 ++++++++++++++++++++++++++-- src/routes.rs | 29 ++++++++++++++++++++++ templates/table.html | 32 +++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 src/db.rs create mode 100644 src/routes.rs create mode 100644 templates/table.html diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..49a2b12 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,57 @@ +use rusqlite::{Connection, Result}; +use std::sync::Mutex; + + use rusqlite::types::Value; + +pub struct Db { + conn: Mutex, +} + +impl Db { + pub fn open(path: &str) -> Result { + Ok(Self { + conn: Mutex::new(Connection::open(path)?), + }) + } + + pub fn get_users(&self) -> Result<(Vec, Vec>)> { + let conn = self.conn.lock().unwrap(); + + let mut stmt = conn.prepare("SELECT * FROM users")?; + + let columns = stmt + .column_names() + .iter() + .map(|s| s.to_string()) + .collect::>(); + + let col_count = stmt.column_count(); + + let rows_iter = stmt.query_map([], move |row| { + let mut r = Vec::new(); + + for i in 0..col_count { + let val: Value = row.get(i)?; + + let s = match val { + Value::Null => "".to_string(), + Value::Integer(i) => i.to_string(), + Value::Real(f) => f.to_string(), + Value::Text(t) => t, // already String + Value::Blob(_) => "".to_string(), + }; + + r.push(s); + } + + Ok(r) + })?; + + let mut rows = Vec::new(); + for r in rows_iter { + rows.push(r?); + } + + Ok((columns, rows)) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e7a11a9..bcd281d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,36 @@ -fn main() { - println!("Hello, world!"); +use axum::{routing::get, Router}; +use clap::Parser; +use std::sync::Arc; +use tokio::net::TcpListener; + +mod db; +mod routes; + +use db::Db; + +#[derive(Parser)] +struct Args { + #[arg(long)] + db: String, } + +#[tokio::main] +async fn main() { + let args = Args::parse(); + + let db = Arc::new(Db::open(&args.db).expect("db open failed")); + + let app = Router::new() + .route("/", get(routes::index)) + .with_state(db); + + let listener = TcpListener::bind("127.0.0.1:8040") + .await + .unwrap(); + + println!("http://127.0.0.1:8040"); + + axum::serve(listener, app) + .await + .unwrap(); +} \ No newline at end of file diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..61bcfdf --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,29 @@ +use askama::Template; // REQUIRED + +use axum::{ + extract::State, + response::Html, +}; +use std::sync::Arc; + +use crate::db::Db; + +#[derive(Template)] +#[template(path = "table.html")] +pub struct TableTemplate { + pub table_name: String, + pub columns: Vec, + pub rows: Vec>, +} + +pub async fn index(State(db): State>) -> Html { + let (columns, rows) = db.get_users().unwrap(); + + let tmpl = TableTemplate { + table_name: "users".into(), + columns, + rows, + }; + + Html(tmpl.render().unwrap()) +} \ No newline at end of file diff --git a/templates/table.html b/templates/table.html new file mode 100644 index 0000000..04a8aee --- /dev/null +++ b/templates/table.html @@ -0,0 +1,32 @@ + + + + + {{ table_name }} + + + +

{{ table_name }}

+ + + + + {% for col in columns %} + + {% endfor %} + + + + + {% for row in rows %} + + {% for cell in row %} + + {% endfor %} + + {% endfor %} + +
{{ col }}
{{ cell }}
+ + + \ No newline at end of file