Game Version types, indexing, and bugfixes (#91)

* Add types to game_versions, allow filtering by version type

- Fixes an issue with version numbers in the initial mod indexing
  queue
- Modifies the /api/v1/categories/game_versions route to take an
  optional query parameter `type` to filter the listed game versions
- Creating tags is now idempotent
- Creating game_versions now requires a JSON body that specifies
  the version type

* Implement automatic indexing of new Minecraft versions

It's currently set to run every 6 hours and isn't configurable; we
could add config for it, but it doesn't seem likely to be rate
limited or have issues with frequency.
This commit is contained in:
Aeledfyr
2020-10-28 11:11:49 -05:00
committed by GitHub
parent ef28459b61
commit a4ba6d1444
7 changed files with 270 additions and 80 deletions

View File

@@ -130,6 +130,7 @@ impl<'a> CategoryBuilder<'a> {
"
INSERT INTO categories (category)
VALUES ($1)
ON CONFLICT (category) DO NOTHING
RETURNING id
",
self.name
@@ -255,6 +256,7 @@ impl<'a> LoaderBuilder<'a> {
"
INSERT INTO loaders (loader)
VALUES ($1)
ON CONFLICT (loader) DO NOTHING
RETURNING id
",
self.name
@@ -266,13 +268,15 @@ impl<'a> LoaderBuilder<'a> {
}
}
#[derive(Default)]
pub struct GameVersionBuilder<'a> {
pub version: Option<&'a str>,
pub version_type: Option<&'a str>,
}
impl GameVersion {
pub fn builder() -> GameVersionBuilder<'static> {
GameVersionBuilder { version: None }
GameVersionBuilder::default()
}
pub async fn get_id<'a, E>(
@@ -302,7 +306,7 @@ impl GameVersion {
Ok(result.map(|r| GameVersionId(r.id)))
}
pub async fn get_name<'a, E>(id: VersionId, exec: E) -> Result<String, DatabaseError>
pub async fn get_name<'a, E>(id: GameVersionId, exec: E) -> Result<String, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
@@ -311,7 +315,7 @@ impl GameVersion {
SELECT version FROM game_versions
WHERE id = $1
",
id as VersionId
id as GameVersionId
)
.fetch_one(exec)
.await?;
@@ -336,6 +340,25 @@ impl GameVersion {
Ok(result)
}
pub async fn list_type<'a, E>(version_type: &str, exec: E) -> Result<Vec<String>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
let result = sqlx::query!(
"
SELECT version FROM game_versions
WHERE type = $1
",
version_type
)
.fetch_many(exec)
.try_filter_map(|e| async { Ok(e.right().map(|c| c.version)) })
.try_collect::<Vec<String>>()
.await?;
Ok(result)
}
pub async fn remove<'a, E>(name: &str, exec: E) -> Result<Option<()>, DatabaseError>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
@@ -370,23 +393,44 @@ impl<'a> GameVersionBuilder<'a> {
{
Ok(Self {
version: Some(version),
..self
})
} else {
Err(DatabaseError::InvalidIdentifier(version.to_string()))
}
}
pub fn version_type(
self,
version_type: &'a str,
) -> Result<GameVersionBuilder<'a>, DatabaseError> {
if version_type
.chars()
.all(|c| c.is_ascii_alphanumeric() || "-_.".contains(c))
{
Ok(Self {
version_type: Some(version_type),
..self
})
} else {
Err(DatabaseError::InvalidIdentifier(version_type.to_string()))
}
}
pub async fn insert<'b, E>(self, exec: E) -> Result<GameVersionId, DatabaseError>
where
E: sqlx::Executor<'b, Database = sqlx::Postgres>,
{
let result = sqlx::query!(
"
INSERT INTO game_versions (version)
VALUES ($1)
INSERT INTO game_versions (version, type)
VALUES ($1, $2)
ON CONFLICT (version) DO UPDATE
SET type = excluded.type
RETURNING id
",
self.version
self.version,
self.version_type,
)
.fetch_one(exec)
.await?;