Merge branch 'ui'

This commit is contained in:
JMARyA 2025-02-18 18:55:44 +01:00
commit 4d14a22642
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
65 changed files with 13177 additions and 405 deletions

View file

@ -1,19 +1,23 @@
#![feature(const_vec_string_slice)]
use data_encoding::HEXUPPER;
use rand::RngCore;
use tokio::sync::OnceCell;
pub mod asset;
pub mod auth;
pub mod format;
#[cfg(feature = "htmx")]
pub mod htmx;
pub mod page;
pub mod request;
pub mod result;
pub mod ui;
// TODO : CORS?
// Postgres
// TODO : IDEA
// more efficient table join using WHERE ANY instead of multiple SELECTs
// map_tables(Vec<T>, Fn(&T) -> U) -> Vec<U>
pub static PG: OnceCell<sqlx::PgPool> = OnceCell::const_new();
/// A macro to retrieve or initialize the `PostgreSQL` connection pool.
@ -51,3 +55,94 @@ pub fn gen_random(token_length: usize) -> String {
HEXUPPER.encode(&token_bytes)
}
fn transpose<T: Clone>(matrix: Vec<Vec<T>>) -> Vec<Vec<T>> {
if matrix.is_empty() {
return vec![];
}
let row_len = matrix[0].len();
let mut transposed = vec![Vec::with_capacity(matrix.len()); row_len];
for row in matrix {
for (i, elem) in row.into_iter().enumerate() {
transposed[i].push(elem);
}
}
transposed
}
// TODO : More types
#[derive(Clone)]
pub enum DatabaseType {
TEXT(String),
INTEGER(i32),
}
impl DatabaseType {
pub fn type_name(&self) -> &str {
match self {
Self::TEXT(_) => "TEXT",
Self::INTEGER(_) => "INTEGER",
}
}
pub fn as_integer(self) -> i32 {
match self {
DatabaseType::INTEGER(result) => return result,
_ => panic!("Wrong DB type"),
}
}
pub fn as_text(self) -> String {
match self {
DatabaseType::TEXT(result) => return result,
_ => panic!("Wrong DB type"),
}
}
}
pub async fn batch_insert(table: &str, values: &[String], entries: Vec<Vec<DatabaseType>>) {
assert_eq!(values.len(), entries.first().unwrap().len());
let mut cmd = format!("INSERT INTO {table} (");
cmd.push_str(&values.join(", "));
cmd.push_str(") SELECT * FROM UNNEST(");
let entries = transpose(entries);
for i in 0..values.len() {
let t = entries.get(i).unwrap().first().unwrap().type_name();
if i == (entries.len() - 1) {
cmd.push_str(&format!("${}::{t}[]", i + 1));
} else {
cmd.push_str(&format!("${}::{t}[],", i + 1));
}
}
cmd.push_str(")");
log::debug!("Executing batch query: {cmd}");
let mut query = sqlx::query(&cmd);
for e in entries {
let first = e.first().unwrap();
match first {
DatabaseType::TEXT(_) => {
query = query.bind(e.into_iter().map(|x| x.as_text()).collect::<Vec<_>>());
}
DatabaseType::INTEGER(_) => {
query = query.bind(e.into_iter().map(|x| x.as_integer()).collect::<Vec<_>>());
}
}
}
query.execute(get_pg!()).await.unwrap();
}
// TODO : LibraryIndex
// index, cleanup, add_one, remove_one, get, exists, query