Files
AstralRinth/src/database/models/categories.rs
Wyatt Verchere ae1c5342f2 Search test + v3 (#731)
* search patch for accurate loader/gv filtering

* backup

* basic search test

* finished test

* incomplete commit; backing up

* Working multipat reroute backup

* working rough draft v3

* most tests passing

* works

* search v2 conversion

* added some tags.rs v2 conversions

* Worked through warnings, unwraps, prints

* refactors

* new search test

* version files changes fixes

* redesign to revs

* removed old caches

* removed games

* fmt clippy

* merge conflicts

* fmt, prepare

* moved v2 routes over to v3

* fixes; tests passing

* project type changes

* moved files over

* fmt, clippy, prepare, etc

* loaders to loader_fields, added tests

* fmt, clippy, prepare

* fixed sorting bug

* reversed back- wrong order for consistency

* fmt; clippy; prepare

---------

Co-authored-by: Jai A <jaiagr+gpg@pm.me>
2023-11-11 16:40:10 -08:00

285 lines
7.2 KiB
Rust

use std::collections::HashMap;
use crate::database::redis::RedisPool;
use super::ids::*;
use super::DatabaseError;
use futures::TryStreamExt;
use serde::{Deserialize, Serialize};
const TAGS_NAMESPACE: &str = "tags";
pub struct ProjectType {
pub id: ProjectTypeId,
pub name: String,
}
#[derive(Serialize, Deserialize)]
pub struct Category {
pub id: CategoryId,
pub category: String,
pub project_type: String,
pub icon: String,
pub header: String,
}
pub struct ReportType {
pub id: ReportTypeId,
pub report_type: String,
}
#[derive(Serialize, Deserialize)]
pub struct DonationPlatform {
pub id: DonationPlatformId,
pub short: String,
pub name: String,
}
impl Category {
// Gets hashmap of category ids matching a name
// Multiple categories can have the same name, but different project types, so we need to return a hashmap
// ProjectTypeId -> CategoryId
pub async fn get_ids<'a, E>(
name: &str,
exec: E,
) -> Result<HashMap<ProjectTypeId, CategoryId>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let result = sqlx::query!(
"
SELECT id, project_type FROM categories
WHERE category = $1
",
name,
)
.fetch_all(exec)
.await?;
let mut map = HashMap::new();
for r in result {
map.insert(ProjectTypeId(r.project_type), CategoryId(r.id));
}
Ok(map)
}
pub async fn get_id_project<'a, E>(
name: &str,
project_type: ProjectTypeId,
exec: E,
) -> Result<Option<CategoryId>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let result = sqlx::query!(
"
SELECT id FROM categories
WHERE category = $1 AND project_type = $2
",
name,
project_type as ProjectTypeId
)
.fetch_optional(exec)
.await?;
Ok(result.map(|r| CategoryId(r.id)))
}
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<Category>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let res: Option<Vec<Category>> = redis
.get_deserialized_from_json(TAGS_NAMESPACE, "category")
.await?;
if let Some(res) = res {
return Ok(res);
}
let result = sqlx::query!(
"
SELECT c.id id, c.category category, c.icon icon, c.header category_header, pt.name project_type
FROM categories c
INNER JOIN project_types pt ON c.project_type = pt.id
ORDER BY c.ordering, c.category
"
)
.fetch_many(exec)
.try_filter_map(|e| async {
Ok(e.right().map(|c| Category {
id: CategoryId(c.id),
category: c.category,
project_type: c.project_type,
icon: c.icon,
header: c.category_header
}))
})
.try_collect::<Vec<Category>>()
.await?;
redis
.set_serialized_to_json(TAGS_NAMESPACE, "category", &result, None)
.await?;
Ok(result)
}
}
impl DonationPlatform {
pub async fn get_id<'a, E>(
id: &str,
exec: E,
) -> Result<Option<DonationPlatformId>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let result = sqlx::query!(
"
SELECT id FROM donation_platforms
WHERE short = $1
",
id
)
.fetch_optional(exec)
.await?;
Ok(result.map(|r| DonationPlatformId(r.id)))
}
pub async fn list<'a, E>(
exec: E,
redis: &RedisPool,
) -> Result<Vec<DonationPlatform>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let res: Option<Vec<DonationPlatform>> = redis
.get_deserialized_from_json(TAGS_NAMESPACE, "donation_platform")
.await?;
if let Some(res) = res {
return Ok(res);
}
let result = sqlx::query!(
"
SELECT id, short, name FROM donation_platforms
"
)
.fetch_many(exec)
.try_filter_map(|e| async {
Ok(e.right().map(|c| DonationPlatform {
id: DonationPlatformId(c.id),
short: c.short,
name: c.name,
}))
})
.try_collect::<Vec<DonationPlatform>>()
.await?;
redis
.set_serialized_to_json(TAGS_NAMESPACE, "donation_platform", &result, None)
.await?;
Ok(result)
}
}
impl ReportType {
pub async fn get_id<'a, E>(name: &str, exec: E) -> Result<Option<ReportTypeId>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let result = sqlx::query!(
"
SELECT id FROM report_types
WHERE name = $1
",
name
)
.fetch_optional(exec)
.await?;
Ok(result.map(|r| ReportTypeId(r.id)))
}
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<String>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let res: Option<Vec<String>> = redis
.get_deserialized_from_json(TAGS_NAMESPACE, "report_type")
.await?;
if let Some(res) = res {
return Ok(res);
}
let result = sqlx::query!(
"
SELECT name FROM report_types
"
)
.fetch_many(exec)
.try_filter_map(|e| async { Ok(e.right().map(|c| c.name)) })
.try_collect::<Vec<String>>()
.await?;
redis
.set_serialized_to_json(TAGS_NAMESPACE, "report_type", &result, None)
.await?;
Ok(result)
}
}
impl ProjectType {
pub async fn get_id<'a, E>(name: &str, exec: E) -> Result<Option<ProjectTypeId>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let result = sqlx::query!(
"
SELECT id FROM project_types
WHERE name = $1
",
name
)
.fetch_optional(exec)
.await?;
Ok(result.map(|r| ProjectTypeId(r.id)))
}
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<String>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let res: Option<Vec<String>> = redis
.get_deserialized_from_json(TAGS_NAMESPACE, "project_type")
.await?;
if let Some(res) = res {
return Ok(res);
}
let result = sqlx::query!(
"
SELECT name FROM project_types
"
)
.fetch_many(exec)
.try_filter_map(|e| async { Ok(e.right().map(|c| c.name)) })
.try_collect::<Vec<String>>()
.await?;
redis
.set_serialized_to_json(TAGS_NAMESPACE, "project_type", &result, None)
.await?;
Ok(result)
}
}