Skip to content

Commit 38f1237

Browse files
committed
feat(mods): improve /v1/me/mods
1 parent 677fb61 commit 38f1237

File tree

3 files changed

+132
-39
lines changed

3 files changed

+132
-39
lines changed

.sqlx/query-20cc5dba1dbe11790912ff32e24a757ad86edfe06094087b2654c9428a2469d6.json

+96
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/endpoints/developers.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ pub async fn update_profile(
247247
struct GetOwnModsQuery {
248248
#[serde(default = "default_own_mods_status")]
249249
status: ModVersionStatusEnum,
250+
#[serde(default)]
251+
only_owner: bool
250252
}
251253

252254
pub fn default_own_mods_status() -> ModVersionStatusEnum {
@@ -265,7 +267,7 @@ pub async fn get_own_mods(
265267
.acquire()
266268
.await
267269
.or(Err(ApiError::DbAcquireError))?;
268-
let mods: Vec<SimpleDevMod> = Mod::get_all_for_dev(dev.id, query.status, &mut pool).await?;
270+
let mods: Vec<SimpleDevMod> = Mod::get_all_for_dev(dev.id, query.status, query.only_owner, &mut pool).await?;
269271
Ok(HttpResponse::Ok().json(ApiResponse {
270272
error: "".to_string(),
271273
payload: mods,

src/types/models/mod_entity.rs

+33-38
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use semver::Version;
2222
use serde::Serialize;
2323
use sqlx::{
2424
types::chrono::{DateTime, Utc},
25-
PgConnection, Postgres, QueryBuilder,
25+
PgConnection
2626
};
2727
use std::{collections::HashMap, str::FromStr};
2828

@@ -228,16 +228,14 @@ impl Mod {
228228

229229
let gd = query.gd.map(|x| vec![x, GDVersionEnum::All]);
230230

231-
/*
232-
* VERY IMPORTANT MESSAGE BELOW.
233-
* This beautiful chunk of code below uses format!() to reuse the same joins / where clauses
234-
* in 2 queries. This uses prepared statements, the parameters are bound in the queries at the end.
235-
*
236-
* DO NOT, I repeat, DO NOT enter any user input inside the format!().
237-
* I will find you personally if you do so.
238-
*
239-
* - Flame
240-
*/
231+
// VERY IMPORTANT MESSAGE BELOW.
232+
// This beautiful chunk of code below uses format!() to reuse the same joins / where clauses
233+
// in 2 queries. This uses prepared statements, the parameters are bound in the queries at the end.
234+
//
235+
// DO NOT, I repeat, DO NOT enter any user input inside the format!().
236+
// I will find you personally if you do so.
237+
//
238+
// - Flame
241239

242240
let joins_filters = r#"
243241
INNER JOIN mod_versions mv ON m.id = mv.mod_id
@@ -440,9 +438,9 @@ impl Mod {
440438
pub async fn get_all_for_dev(
441439
id: i32,
442440
status: ModVersionStatusEnum,
441+
only_owner: bool,
443442
pool: &mut PgConnection,
444443
) -> Result<Vec<SimpleDevMod>, ApiError> {
445-
#[derive(sqlx::FromRow)]
446444
struct Record {
447445
id: String,
448446
featured: bool,
@@ -455,36 +453,33 @@ impl Mod {
455453
info: Option<String>,
456454
}
457455

458-
let mut query_builder: QueryBuilder<Postgres> = QueryBuilder::new(
459-
"SELECT
460-
m.id, m.featured, m.download_count as mod_download_count,
461-
mv.name, mv.version, mv.download_count as mod_version_download_count,
462-
mvs.info, mvs.status,
463-
exists(
464-
select 1 from mod_version_statuses mvs_inner
465-
where mvs_inner.mod_version_id = mv.id and mvs_inner.status = 'accepted'
466-
) as validated
456+
let records = sqlx::query_as!(
457+
Record,
458+
r#"SELECT
459+
m.id, m.featured, m.download_count as mod_download_count,
460+
mv.name, mv.version, mv.download_count as mod_version_download_count,
461+
mvs.info, mvs.status as "status: _",
462+
exists(
463+
select 1 from mod_version_statuses mvs_inner
464+
where mvs_inner.mod_version_id = mv.id and mvs_inner.status = 'accepted'
465+
) as "validated!: _"
467466
FROM mods m
468467
INNER JOIN mod_versions mv ON m.id = mv.mod_id
469468
INNER JOIN mods_developers md ON md.mod_id = m.id
470469
INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id
471-
WHERE md.developer_id = ",
472-
);
473-
query_builder.push_bind(id);
474-
query_builder.push(" AND mvs.status = ");
475-
query_builder.push_bind(status);
476-
477-
let records = match query_builder
478-
.build_query_as::<Record>()
479-
.fetch_all(&mut *pool)
480-
.await
481-
{
482-
Ok(e) => e,
483-
Err(e) => {
484-
log::error!("{}", e);
485-
return Err(ApiError::DbError);
486-
}
487-
};
470+
WHERE md.developer_id = $1
471+
AND mvs.status = $2
472+
AND ($3 = false OR md.is_owner = true)
473+
ORDER BY m.created_at DESC, mv.id DESC
474+
"#,
475+
id,
476+
status as ModVersionStatusEnum,
477+
only_owner
478+
)
479+
.fetch_all(&mut *pool)
480+
.await
481+
.inspect_err(|x| log::error!("Failed to fetch developer mods: {}", x))
482+
.or(Err(ApiError::DbError))?;
488483

489484
if records.is_empty() {
490485
return Ok(vec![]);

0 commit comments

Comments
 (0)