Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
Version ordering [MOD-551] (#740)
Browse files Browse the repository at this point in the history
* Version ordering

* cargo sqlx prepare

* Use version ordering for maven

* Use version ordering when sorting versions in Rust (not just SQL)

* Thanks clippy
  • Loading branch information
OmegaJak authored Nov 1, 2023
1 parent d5594b0 commit 911d442
Show file tree
Hide file tree
Showing 16 changed files with 392 additions and 27 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions migrations/20231027195838_version_ordering.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE versions ADD COLUMN ordering int NULL;
104 changes: 95 additions & 9 deletions src/database/models/version_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct VersionBuilder {
pub featured: bool,
pub status: VersionStatus,
pub requested_status: Option<VersionStatus>,
pub ordering: Option<i32>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -214,6 +215,7 @@ impl VersionBuilder {
version_type: self.version_type,
status: self.status,
requested_status: self.requested_status,
ordering: self.ordering,
};

version.insert(transaction).await?;
Expand Down Expand Up @@ -317,7 +319,7 @@ impl VersionVersion {
}
}

#[derive(Clone, Deserialize, Serialize)]
#[derive(Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct Version {
pub id: VersionId,
pub project_id: ProjectId,
Expand All @@ -332,6 +334,7 @@ pub struct Version {
pub featured: bool,
pub status: VersionStatus,
pub requested_status: Option<VersionStatus>,
pub ordering: Option<i32>,
}

impl Version {
Expand All @@ -344,12 +347,12 @@ impl Version {
INSERT INTO versions (
id, mod_id, author_id, name, version_number,
changelog, date_published, downloads,
version_type, featured, status
version_type, featured, status, ordering
)
VALUES (
$1, $2, $3, $4, $5,
$6, $7, $8,
$9, $10, $11
$9, $10, $11, $12
)
",
self.id as VersionId,
Expand All @@ -362,7 +365,8 @@ impl Version {
self.downloads,
&self.version_type,
self.featured,
self.status.as_str()
self.status.as_str(),
self.ordering
)
.execute(&mut **transaction)
.await?;
Expand Down Expand Up @@ -554,7 +558,7 @@ impl Version {
"
SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,
v.changelog changelog, v.date_published date_published, v.downloads downloads,
v.version_type version_type, v.featured featured, v.status status, v.requested_status requested_status,
v.version_type version_type, v.featured featured, v.status status, v.requested_status requested_status, v.ordering ordering,
JSONB_AGG(DISTINCT jsonb_build_object('version', gv.version, 'created', gv.created)) filter (where gv.version is not null) game_versions,
ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders,
JSONB_AGG(DISTINCT jsonb_build_object('id', f.id, 'url', f.url, 'filename', f.filename, 'primary', f.is_primary, 'size', f.size, 'file_type', f.file_type)) filter (where f.id is not null) files,
Expand All @@ -570,7 +574,7 @@ impl Version {
LEFT OUTER JOIN dependencies d on v.id = d.dependent_id
WHERE v.id = ANY($1)
GROUP BY v.id
ORDER BY v.date_published ASC;
ORDER BY v.ordering ASC NULLS LAST, v.date_published ASC;
",
&version_ids_parsed
)
Expand All @@ -593,6 +597,7 @@ impl Version {
status: VersionStatus::from_string(&v.status),
requested_status: v.requested_status
.map(|x| VersionStatus::from_string(&x)),
ordering: v.ordering,
},
files: {
#[derive(Deserialize)]
Expand Down Expand Up @@ -851,7 +856,7 @@ impl Version {
}
}

#[derive(Clone, Deserialize, Serialize)]
#[derive(Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct QueryVersion {
pub inner: Version,

Expand All @@ -861,15 +866,15 @@ pub struct QueryVersion {
pub dependencies: Vec<QueryDependency>,
}

#[derive(Clone, Deserialize, Serialize)]
#[derive(Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct QueryDependency {
pub project_id: Option<ProjectId>,
pub version_id: Option<VersionId>,
pub file_name: Option<String>,
pub dependency_type: String,
}

#[derive(Clone, Deserialize, Serialize)]
#[derive(Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct QueryFile {
pub id: FileId,
pub url: String,
Expand All @@ -892,3 +897,84 @@ pub struct SingleFile {
pub size: u32,
pub file_type: Option<FileType>,
}

impl std::cmp::Ord for QueryVersion {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.inner.cmp(&other.inner)
}
}

impl std::cmp::PartialOrd for QueryVersion {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl std::cmp::Ord for Version {
fn cmp(&self, other: &Self) -> Ordering {
let ordering_order = match (self.ordering, other.ordering) {
(None, None) => Ordering::Equal,
(None, Some(_)) => Ordering::Greater,
(Some(_), None) => Ordering::Less,
(Some(a), Some(b)) => a.cmp(&b),
};

match ordering_order {
Ordering::Equal => self.date_published.cmp(&other.date_published),
ordering => ordering,
}
}
}

impl std::cmp::PartialOrd for Version {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

#[cfg(test)]
mod tests {
use chrono::Months;

use super::*;

#[test]
fn test_version_sorting() {
let versions = vec![
get_version(4, None, months_ago(6)),
get_version(3, None, months_ago(7)),
get_version(2, Some(1), months_ago(6)),
get_version(1, Some(0), months_ago(4)),
get_version(0, Some(0), months_ago(5)),
];

let sorted = versions.iter().cloned().sorted().collect_vec();

let expected_sorted_ids = vec![0, 1, 2, 3, 4];
let actual_sorted_ids = sorted.iter().map(|v| v.id.0).collect_vec();
assert_eq!(expected_sorted_ids, actual_sorted_ids);
}

fn months_ago(months: u32) -> DateTime<Utc> {
Utc::now().checked_sub_months(Months::new(months)).unwrap()
}

fn get_version(id: i64, ordering: Option<i32>, date_published: DateTime<Utc>) -> Version {
Version {
id: VersionId(id),
ordering,
date_published,
project_id: ProjectId(0),
author_id: UserId(0),
name: Default::default(),
version_number: Default::default(),
changelog: Default::default(),
changelog_url: Default::default(),
downloads: Default::default(),
version_type: Default::default(),
featured: Default::default(),
status: VersionStatus::Listed,
requested_status: Default::default(),
}
}
}
5 changes: 4 additions & 1 deletion src/models/projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ pub struct Version {
pub game_versions: Vec<GameVersion>,
/// The loaders that this version works on
pub loaders: Vec<Loader>,
/// Ordering override, lower is returned first
pub ordering: Option<i32>,
}

impl From<QueryVersion> for Version {
Expand All @@ -515,6 +517,7 @@ impl From<QueryVersion> for Version {
"alpha" => VersionType::Alpha,
_ => VersionType::Release,
},
ordering: v.ordering,

status: v.status,
requested_status: v.requested_status,
Expand Down Expand Up @@ -729,7 +732,7 @@ impl DependencyType {
}
}

#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub enum FileType {
RequiredResourcePack,
Expand Down
2 changes: 1 addition & 1 deletion src/routes/maven.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub async fn maven_metadata(
SELECT id, version_number, version_type
FROM versions
WHERE mod_id = $1 AND status = ANY($2)
ORDER BY date_published ASC
ORDER BY ordering ASC NULLS LAST, date_published ASC
",
project.inner.id as database::models::ids::ProjectId,
&*crate::models::projects::VersionStatus::iterator()
Expand Down
1 change: 1 addition & 0 deletions src/routes/v2/project_creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,7 @@ async fn create_initial_version(
status: VersionStatus::Listed,
version_type: version_data.release_channel.to_string(),
requested_status: None,
ordering: version_data.ordering,
};

Ok(version)
Expand Down
5 changes: 5 additions & 0 deletions src/routes/v2/version_creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ pub struct InitialVersionData {
#[validate(length(max = 10))]
#[serde(default)]
pub uploaded_images: Vec<ImageId>,

// The ordering relative to other versions
pub ordering: Option<i32>,
}

#[derive(Serialize, Deserialize, Clone)]
Expand Down Expand Up @@ -316,6 +319,7 @@ async fn version_create_inner(
featured: version_create_data.featured,
status: version_create_data.status,
requested_status: None,
ordering: version_create_data.ordering,
});

return Ok(());
Expand Down Expand Up @@ -427,6 +431,7 @@ async fn version_create_inner(
version_type: version_data.release_channel,
status: builder.status,
requested_status: builder.requested_status,
ordering: builder.ordering,
files: builder
.files
.iter()
Expand Down
Loading

0 comments on commit 911d442

Please sign in to comment.