split route code
This commit is contained in:
parent
e7913736e5
commit
272b5eb61c
25
src/lib.rs
25
src/lib.rs
@ -1,5 +1,5 @@
|
|||||||
use axum::{Router, body::Body, response::Response, routing::get};
|
use axum::{body::Body, response::Response, routing::get, Router};
|
||||||
use maud::{Markup, html};
|
use maud::{html, Markup};
|
||||||
use partials::page;
|
use partials::page;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -79,11 +79,24 @@ async fn serve_marker_png() -> Response<Body> {
|
|||||||
async fn index(session: Session) -> Markup {
|
async fn index(session: Session) -> Markup {
|
||||||
let content = html! {
|
let content = html! {
|
||||||
h1 { "Stationslauf-App" }
|
h1 { "Stationslauf-App" }
|
||||||
a role="button" href="/station" {
|
nav {
|
||||||
"Stationen"
|
ul {
|
||||||
|
li {
|
||||||
|
a role="button" href="/station" {
|
||||||
|
"Stationen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
a role="button" href="/route" {
|
||||||
|
"Routen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
a role="button" href="/group" {
|
||||||
|
"Gruppen"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
a role="button" href="/route" {
|
|
||||||
"Routen"
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
page(content, session, false).await
|
page(content, session, false).await
|
||||||
|
167
src/route/mod.rs
Normal file
167
src/route/mod.rs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
use crate::station::Station;
|
||||||
|
use axum::Router;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::{FromRow, SqlitePool};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
mod web;
|
||||||
|
|
||||||
|
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
||||||
|
pub(crate) struct Route {
|
||||||
|
pub(crate) id: i64,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Route {
|
||||||
|
async fn all(db: &SqlitePool) -> Vec<Self> {
|
||||||
|
sqlx::query_as::<_, Self>("SELECT id, name FROM route;")
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
|
||||||
|
sqlx::query_as!(Self, "SELECT id, name FROM route WHERE id = ?", id)
|
||||||
|
.fetch_one(db)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create(db: &SqlitePool, name: &str) -> Result<(), String> {
|
||||||
|
sqlx::query!("INSERT INTO route(name) VALUES (?)", name)
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_name(&self, db: &SqlitePool, name: &str) {
|
||||||
|
sqlx::query!("UPDATE route SET name = ? WHERE id = ?", name, self.id)
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn add_station(&self, db: &SqlitePool, station: &Station) -> Result<(), String> {
|
||||||
|
sqlx::query!(
|
||||||
|
r#"
|
||||||
|
INSERT INTO route_station (route_id, station_id, pos)
|
||||||
|
VALUES (?, ?, (
|
||||||
|
SELECT COALESCE(MAX(pos), 0) + 2
|
||||||
|
FROM route_station
|
||||||
|
WHERE route_id = ?
|
||||||
|
))
|
||||||
|
"#,
|
||||||
|
self.id,
|
||||||
|
station.id,
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete_station(&self, db: &SqlitePool, station: &Station) -> bool {
|
||||||
|
let result = sqlx::query!(
|
||||||
|
"DELETE FROM route_station WHERE route_id = ? AND station_id = ?",
|
||||||
|
self.id,
|
||||||
|
station.id
|
||||||
|
)
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
result.rows_affected() > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn move_station_higher(&self, db: &SqlitePool, station: &Station) -> bool {
|
||||||
|
let result = sqlx::query!(
|
||||||
|
"UPDATE route_station SET pos = pos-3 WHERE route_id = ? AND station_id = ?",
|
||||||
|
self.id,
|
||||||
|
station.id
|
||||||
|
)
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if result.rows_affected() == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
&format!(
|
||||||
|
"
|
||||||
|
-- Step 1: Create a temporary table with new rank values
|
||||||
|
CREATE TEMP TABLE IF NOT EXISTS temp_pos AS
|
||||||
|
SELECT
|
||||||
|
route_id,
|
||||||
|
station_id,
|
||||||
|
ROW_NUMBER() OVER (ORDER BY pos ASC) AS new_rank
|
||||||
|
FROM
|
||||||
|
route_station WHERE route_id = {};
|
||||||
|
|
||||||
|
-- Step 2: Update the original table
|
||||||
|
UPDATE route_station
|
||||||
|
SET pos = (SELECT 2*new_rank FROM temp_pos WHERE temp_pos.route_id = route_station.route_id AND temp_pos.station_id = route_station.station_id) WHERE route_id = {};
|
||||||
|
|
||||||
|
-- Step 3: Drop the temporary table (no longer needed)
|
||||||
|
DROP TABLE temp_pos;",
|
||||||
|
self.id,
|
||||||
|
self.id,
|
||||||
|
))
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete(&self, db: &SqlitePool) -> Result<(), String> {
|
||||||
|
sqlx::query!("DELETE FROM route WHERE id = ?", self.id)
|
||||||
|
.execute(db)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn stations(&self, db: &SqlitePool) -> Vec<Station> {
|
||||||
|
sqlx::query_as::<_, Station>(
|
||||||
|
"
|
||||||
|
SELECT s.id, s.name, s.notes, s.amount_people, s.last_login, s.pw, s.lat, s.lng
|
||||||
|
FROM station s
|
||||||
|
JOIN route_station rs ON s.id = rs.station_id
|
||||||
|
WHERE rs.route_id = ?
|
||||||
|
ORDER BY rs.pos
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(self.id)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn stations_not_in_route(&self, db: &SqlitePool) -> Vec<Station> {
|
||||||
|
sqlx::query_as::<_, Station>(
|
||||||
|
"
|
||||||
|
SELECT id, name, notes, amount_people, last_login, pw, lat, lng
|
||||||
|
FROM station
|
||||||
|
WHERE id NOT IN (
|
||||||
|
SELECT station_id
|
||||||
|
FROM route_station
|
||||||
|
WHERE route_id = ?
|
||||||
|
)
|
||||||
|
ORDER BY name
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(self.id)
|
||||||
|
.fetch_all(db)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn routes() -> Router<Arc<SqlitePool>> {
|
||||||
|
web::routes()
|
||||||
|
}
|
@ -1,172 +1,17 @@
|
|||||||
|
use super::Route;
|
||||||
use crate::{err, page, station::Station, succ};
|
use crate::{err, page, station::Station, succ};
|
||||||
use axum::{
|
use axum::{
|
||||||
Form, Router,
|
|
||||||
extract::State,
|
extract::State,
|
||||||
response::{IntoResponse, Redirect},
|
response::{IntoResponse, Redirect},
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
|
Form, Router,
|
||||||
};
|
};
|
||||||
use maud::{Markup, PreEscaped, html};
|
use maud::{html, Markup, PreEscaped};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::Deserialize;
|
||||||
use sqlx::{FromRow, SqlitePool};
|
use sqlx::SqlitePool;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tower_sessions::Session;
|
use tower_sessions::Session;
|
||||||
|
|
||||||
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
|
||||||
pub(crate) struct Route {
|
|
||||||
pub(crate) id: i64,
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Route {
|
|
||||||
async fn all(db: &SqlitePool) -> Vec<Self> {
|
|
||||||
sqlx::query_as::<_, Self>("SELECT id, name FROM route;")
|
|
||||||
.fetch_all(db)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn find_by_id(db: &SqlitePool, id: i64) -> Option<Self> {
|
|
||||||
sqlx::query_as!(Self, "SELECT id, name FROM route WHERE id = ?", id)
|
|
||||||
.fetch_one(db)
|
|
||||||
.await
|
|
||||||
.ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create(db: &SqlitePool, name: &str) -> Result<(), String> {
|
|
||||||
sqlx::query!("INSERT INTO route(name) VALUES (?)", name)
|
|
||||||
.execute(db)
|
|
||||||
.await
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn update_name(&self, db: &SqlitePool, name: &str) {
|
|
||||||
sqlx::query!("UPDATE route SET name = ? WHERE id = ?", name, self.id)
|
|
||||||
.execute(db)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add_station(&self, db: &SqlitePool, station: &Station) -> Result<(), String> {
|
|
||||||
sqlx::query!(
|
|
||||||
r#"
|
|
||||||
INSERT INTO route_station (route_id, station_id, pos)
|
|
||||||
VALUES (?, ?, (
|
|
||||||
SELECT COALESCE(MAX(pos), 0) + 2
|
|
||||||
FROM route_station
|
|
||||||
WHERE route_id = ?
|
|
||||||
))
|
|
||||||
"#,
|
|
||||||
self.id,
|
|
||||||
station.id,
|
|
||||||
self.id
|
|
||||||
)
|
|
||||||
.execute(db)
|
|
||||||
.await
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn delete_station(&self, db: &SqlitePool, station: &Station) -> bool {
|
|
||||||
let result = sqlx::query!(
|
|
||||||
"DELETE FROM route_station WHERE route_id = ? AND station_id = ?",
|
|
||||||
self.id,
|
|
||||||
station.id
|
|
||||||
)
|
|
||||||
.execute(db)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
result.rows_affected() > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn move_station_higher(&self, db: &SqlitePool, station: &Station) -> bool {
|
|
||||||
let result = sqlx::query!(
|
|
||||||
"UPDATE route_station SET pos = pos-3 WHERE route_id = ? AND station_id = ?",
|
|
||||||
self.id,
|
|
||||||
station.id
|
|
||||||
)
|
|
||||||
.execute(db)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if result.rows_affected() == 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlx::query(
|
|
||||||
&format!(
|
|
||||||
"
|
|
||||||
-- Step 1: Create a temporary table with new rank values
|
|
||||||
CREATE TEMP TABLE IF NOT EXISTS temp_pos AS
|
|
||||||
SELECT
|
|
||||||
route_id,
|
|
||||||
station_id,
|
|
||||||
ROW_NUMBER() OVER (ORDER BY pos ASC) AS new_rank
|
|
||||||
FROM
|
|
||||||
route_station WHERE route_id = {};
|
|
||||||
|
|
||||||
-- Step 2: Update the original table
|
|
||||||
UPDATE route_station
|
|
||||||
SET pos = (SELECT 2*new_rank FROM temp_pos WHERE temp_pos.route_id = route_station.route_id AND temp_pos.station_id = route_station.station_id) WHERE route_id = {};
|
|
||||||
|
|
||||||
-- Step 3: Drop the temporary table (no longer needed)
|
|
||||||
DROP TABLE temp_pos;",
|
|
||||||
self.id,
|
|
||||||
self.id,
|
|
||||||
))
|
|
||||||
.execute(db)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn delete(&self, db: &SqlitePool) -> Result<(), String> {
|
|
||||||
sqlx::query!("DELETE FROM route WHERE id = ?", self.id)
|
|
||||||
.execute(db)
|
|
||||||
.await
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn stations(&self, db: &SqlitePool) -> Vec<Station> {
|
|
||||||
sqlx::query_as::<_, Station>(
|
|
||||||
"
|
|
||||||
SELECT s.id, s.name, s.notes, s.amount_people, s.last_login, s.pw, s.lat, s.lng
|
|
||||||
FROM station s
|
|
||||||
JOIN route_station rs ON s.id = rs.station_id
|
|
||||||
WHERE rs.route_id = ?
|
|
||||||
ORDER BY rs.pos
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.bind(self.id)
|
|
||||||
.fetch_all(db)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn stations_not_in_route(&self, db: &SqlitePool) -> Vec<Station> {
|
|
||||||
sqlx::query_as::<_, Station>(
|
|
||||||
"
|
|
||||||
SELECT id, name, notes, amount_people, last_login, pw, lat, lng
|
|
||||||
FROM station
|
|
||||||
WHERE id NOT IN (
|
|
||||||
SELECT station_id
|
|
||||||
FROM route_station
|
|
||||||
WHERE route_id = ?
|
|
||||||
)
|
|
||||||
ORDER BY name
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.bind(self.id)
|
|
||||||
.fetch_all(db)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
async fn index(State(db): State<Arc<SqlitePool>>, session: Session) -> Markup {
|
||||||
let routes = Route::all(&db).await;
|
let routes = Route::all(&db).await;
|
||||||
|
|
@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use sqlx::{FromRow, SqlitePool};
|
use sqlx::{FromRow, SqlitePool};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod routes;
|
mod web;
|
||||||
|
|
||||||
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
||||||
pub(crate) struct Station {
|
pub(crate) struct Station {
|
||||||
@ -130,5 +130,5 @@ impl Station {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn routes() -> Router<Arc<SqlitePool>> {
|
pub(super) fn routes() -> Router<Arc<SqlitePool>> {
|
||||||
routes::routes()
|
web::routes()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user