generated from alecodes/base-template
feat: add sqlx transaction extractor to router
This commit is contained in:
parent
cfaf7ecc1f
commit
a662b94b21
8 changed files with 79 additions and 14 deletions
|
|
@ -16,6 +16,9 @@ migrate: (docker-compose "run dbmate migrate")
|
||||||
|
|
||||||
rollback: (docker-compose "run dbmate rollback")
|
rollback: (docker-compose "run dbmate rollback")
|
||||||
|
|
||||||
|
build-frontend-watch:
|
||||||
|
watchexec --restart --watch frontend just build-frontend
|
||||||
|
|
||||||
build-frontend:
|
build-frontend:
|
||||||
#!/usr/bin/env bun
|
#!/usr/bin/env bun
|
||||||
import sassPlugin from "@alecodes/bun-plugin-sass";
|
import sassPlugin from "@alecodes/bun-plugin-sass";
|
||||||
|
|
|
||||||
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -69,6 +69,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
|
checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum-core",
|
"axum-core",
|
||||||
|
"axum-macros",
|
||||||
"bytes",
|
"bytes",
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
|
@ -116,6 +117,17 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-macros"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-sqlx-tx"
|
name = "axum-sqlx-tx"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
|
@ -226,7 +238,10 @@ checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -236,6 +251,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-sqlx-tx",
|
"axum-sqlx-tx",
|
||||||
|
"chrono",
|
||||||
"minijinja",
|
"minijinja",
|
||||||
"minijinja-embed",
|
"minijinja-embed",
|
||||||
"notify",
|
"notify",
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = "0.8.1"
|
axum = { version = "0.8.1", features = ["macros"] }
|
||||||
axum-sqlx-tx = "0.10.0"
|
axum-sqlx-tx = "0.10.0"
|
||||||
|
chrono = { version = "0.4.39", features = ["serde"] }
|
||||||
minijinja = { version = "2.7.0", features = ["loader"] }
|
minijinja = { version = "2.7.0", features = ["loader"] }
|
||||||
minijinja-embed = "2.7.0"
|
minijinja-embed = "2.7.0"
|
||||||
notify = "8.0.0"
|
notify = "8.0.0"
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ plugins = ["bun-plugin-sass"]
|
||||||
|
|
||||||
[install.scopes]
|
[install.scopes]
|
||||||
|
|
||||||
"@alecodes" = { token = "$NPM_REGISTRY_TOKEN", url = "https://git.alecodes.page/api/packages/alecodes/npm/" }
|
"@alecodes" = { url = "https://git.alecodes.page/api/packages/alecodes/npm/" }
|
||||||
"@mini-strap" = { token = "$NPM_REGISTRY_TOKEN", url = "https://git.alecodes.page/api/packages/alecodes/npm/" }
|
"@mini-strap" = { url = "https://git.alecodes.page/api/packages/alecodes/npm/" }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="msp-text-center">Database</th>
|
||||||
|
<th class="msp-text-center">Version</th>
|
||||||
|
<th class="msp-text-center">Database Name</th>
|
||||||
|
<th class="msp-text-center">Current User</th>
|
||||||
|
<th class="msp-text-center">Current Timestamp</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for row in rows %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ row.database }}</th>
|
||||||
|
<th>{{ row.version }}</th>
|
||||||
|
<th>{{ row.current_database }}</th>
|
||||||
|
<th>{{ row.current_user }}</th>
|
||||||
|
<th>{{ row.current_timestamp }}</th>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock content %}
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
mod error;
|
mod error;
|
||||||
pub mod router;
|
pub mod router;
|
||||||
|
|
||||||
|
use axum::extract::FromRef;
|
||||||
pub use error::{Error, Result, ResultTemplate};
|
pub use error::{Error, Result, ResultTemplate};
|
||||||
use minijinja::{Environment, Template};
|
use minijinja::{Environment, Template};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub type Tx = axum_sqlx_tx::Tx<sqlx::Postgres>;
|
pub type Tx = axum_sqlx_tx::Tx<sqlx::Postgres>;
|
||||||
|
pub type TxState = axum_sqlx_tx::State<sqlx::Postgres>;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Link {
|
pub struct Link {
|
||||||
|
|
@ -15,13 +16,15 @@ pub struct Link {
|
||||||
pub subpages: Vec<Self>,
|
pub subpages: Vec<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, FromRef)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
tmpl_env: Environment<'static>,
|
tmpl_env: Environment<'static>,
|
||||||
|
tx: TxState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
pub fn new(tmpl_env: Environment<'static>) -> Arc<Self> {
|
pub fn new(tmpl_env: Environment<'static>, tx: TxState) -> Self {
|
||||||
Arc::new(AppState { tmpl_env })
|
AppState { tmpl_env, tx }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_template(&self, name: &str) -> Result<Template> {
|
pub fn get_template(&self, name: &str) -> Result<Template> {
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,8 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
let app = router::new()
|
let app = router::new()
|
||||||
.layer(TraceLayer::new_for_http().on_request(()))
|
.layer(TraceLayer::new_for_http().on_request(()))
|
||||||
.with_state(AppState::new(tmpl_env))
|
|
||||||
.layer(tx_layer)
|
.layer(tx_layer)
|
||||||
.with_state(tx_state);
|
.with_state(AppState::new(tmpl_env, tx_state));
|
||||||
|
|
||||||
// Add hot reload only on dev mode
|
// Add hot reload only on dev mode
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,37 @@
|
||||||
use axum::{extract::State, response::Html, routing::get, Router};
|
use axum::{extract::State, response::Html, routing::get, Router};
|
||||||
|
use chrono::Utc;
|
||||||
use minijinja::context;
|
use minijinja::context;
|
||||||
use std::sync::Arc;
|
use serde::Serialize;
|
||||||
|
use sqlx::prelude::FromRow;
|
||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
|
|
||||||
use crate::{AppState, ResultTemplate};
|
use crate::{AppState, ResultTemplate, Tx};
|
||||||
|
|
||||||
pub fn new() -> Router<Arc<AppState>> {
|
pub fn new() -> Router<AppState> {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(handler_home))
|
.route("/", get(handler_home))
|
||||||
.nest_service("/assets", ServeDir::new("dist/assets"))
|
.nest_service("/assets", ServeDir::new("dist/assets"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handler_home(State(state): State<Arc<AppState>>) -> ResultTemplate {
|
#[derive(FromRow, Debug, Serialize)]
|
||||||
let template = state.tmpl_env.get_template("base.html")?;
|
struct ExampleRow {
|
||||||
|
pub database: String,
|
||||||
|
pub version: String,
|
||||||
|
pub current_database: String,
|
||||||
|
pub current_user: String,
|
||||||
|
pub current_timestamp: chrono::DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
let content = template.render(context!())?;
|
async fn handler_home(State(state): State<AppState>, mut tx: Tx) -> ResultTemplate {
|
||||||
|
let template = state.tmpl_env.get_template("index.html")?;
|
||||||
|
|
||||||
|
let rows = sqlx::query_as::<_, ExampleRow>("select 'Postgres' as database, setting as version, current_database(), current_user, current_timestamp from pg_settings where name = 'server_version'")
|
||||||
|
.fetch_all(&mut tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("{:?}", rows);
|
||||||
|
|
||||||
|
let content = template.render(context!(rows => rows))?;
|
||||||
|
|
||||||
Ok(Html(content))
|
Ok(Html(content))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue