From b5378c12967e6cb0798245be00c564196247f213 Mon Sep 17 00:00:00 2001 From: Geometrically Date: Sun, 24 Jan 2021 21:33:32 -0700 Subject: [PATCH 1/4] Query Optimization --- sqlx-data.json | 672 ++++++++++++++++------------ src/database/models/mod_item.rs | 260 ++++++----- src/database/models/version_item.rs | 226 ++++++---- src/routes/mods.rs | 36 +- src/routes/versions.rs | 4 +- 5 files changed, 694 insertions(+), 504 deletions(-) diff --git a/sqlx-data.json b/sqlx-data.json index 85457cdf8..1cb6399aa 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -203,26 +203,6 @@ ] } }, - "0e0057078bce50b61e7fef071389cb6b462472da76abee1d4e1ab952aa8dc4b9": { - "query": "\n SELECT gv.version FROM game_versions_versions gvv\n INNER JOIN game_versions gv ON gvv.game_version_id=gv.id\n WHERE gvv.joining_version_id = $1\n ORDER BY gv.created\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "version", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false - ] - } - }, "1220d15a56dbf823eaa452fbafa17442ab0568bc81a31fa38e16e3df3278e5f9": { "query": "SELECT EXISTS(SELECT 1 FROM users WHERE id = $1)", "describe": { @@ -339,32 +319,6 @@ ] } }, - "1524c0462be70077736ac70fcd037fbf75651456b692e2ce40fa2e3fc8123984": { - "query": "\n SELECT hashes.algorithm, hashes.hash FROM hashes\n WHERE hashes.file_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "algorithm", - "type_info": "Varchar" - }, - { - "ordinal": 1, - "name": "hash", - "type_info": "Bytea" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false, - false - ] - } - }, "16049957962ded08751d5a4ddce2ffac17ecd486f61210c51a952508425d83e6": { "query": "\n UPDATE versions\n SET changelog = $1\n WHERE (id = $2)\n ", "describe": { @@ -537,6 +491,110 @@ ] } }, + "1e932b3ed3a406e860817241dec7616f712c1af59ce041a622a978b3be20ad5b": { + "query": "\n SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,\n v.changelog changelog, v.changelog_url changelog_url, v.date_published date_published, v.downloads downloads,\n rc.channel release_channel, v.featured featured,\n ARRAY_AGG(gv.version ORDER BY gv.created) game_versions, ARRAY_AGG(DISTINCT l.loader) loaders,\n ARRAY_AGG(DISTINCT f.id || ', ' || f.filename || ', ' || f.is_primary || ', ' || f.url) files,\n ARRAY_AGG(DISTINCT h.hash || ', ' || h.algorithm || ', ' || h.file_id) hashes\n FROM versions v\n INNER JOIN release_channels rc on v.release_channel = rc.id\n INNER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n INNER JOIN game_versions gv on gvv.game_version_id = gv.id\n INNER JOIN loaders_versions lv on v.id = lv.version_id\n INNER JOIN loaders l on lv.loader_id = l.id\n INNER JOIN files f on v.id = f.version_id\n INNER JOIN hashes h on f.id = h.file_id\n WHERE v.id = $1\n GROUP BY v.id, rc.id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "mod_id", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "author_id", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "version_name", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "version_number", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "changelog", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "changelog_url", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "date_published", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "downloads", + "type_info": "Int4" + }, + { + "ordinal": 9, + "name": "release_channel", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "featured", + "type_info": "Bool" + }, + { + "ordinal": 11, + "name": "game_versions", + "type_info": "VarcharArray" + }, + { + "ordinal": 12, + "name": "loaders", + "type_info": "VarcharArray" + }, + { + "ordinal": 13, + "name": "files", + "type_info": "TextArray" + }, + { + "ordinal": 14, + "name": "hashes", + "type_info": "TextArray" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + null, + null, + null, + null + ] + } + }, "1ffce9b2d5c9fa6c8b9abce4bad9f9419c44ad6367b7463b979c91b9b5b4fea1": { "query": "SELECT EXISTS(SELECT 1 FROM versions WHERE id=$1)", "describe": { @@ -908,26 +966,6 @@ "nullable": [] } }, - "4411f2aefd43881450da34db81e826110ac86c3a6cef9fd6a3e9e341508d1f09": { - "query": "\n SELECT id FROM versions\n WHERE mod_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false - ] - } - }, "449920c44d498adf8b771973d6034dc97e1c7f3ff4d9d23599af432f294ed564": { "query": "\n INSERT INTO files (id, version_id, url, filename)\n VALUES ($1, $2, $3, $4)\n ", "describe": { @@ -1670,6 +1708,110 @@ "nullable": [] } }, + "7562d8fd242d5f73b94e87affffade9b7a4cef2aecc9dce2e45ee7045a59dbd9": { + "query": "\n SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,\n v.changelog changelog, v.changelog_url changelog_url, v.date_published date_published, v.downloads downloads,\n rc.channel release_channel, v.featured featured,\n ARRAY_AGG(gv.version ORDER BY gv.created) game_versions, ARRAY_AGG(DISTINCT l.loader) loaders,\n ARRAY_AGG(DISTINCT f.id || ', ' || f.filename || ', ' || f.is_primary || ', ' || f.url) files,\n ARRAY_AGG(DISTINCT h.hash || ', ' || h.algorithm || ', ' || h.file_id) hashes\n FROM versions v\n INNER JOIN release_channels rc on v.release_channel = rc.id\n INNER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n INNER JOIN game_versions gv on gvv.game_version_id = gv.id\n INNER JOIN loaders_versions lv on v.id = lv.version_id\n INNER JOIN loaders l on lv.loader_id = l.id\n INNER JOIN files f on v.id = f.version_id\n INNER JOIN hashes h on f.id = h.file_id\n WHERE v.id IN (SELECT * FROM UNNEST($1::bigint[]))\n GROUP BY v.id, rc.id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "mod_id", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "author_id", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "version_name", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "version_number", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "changelog", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "changelog_url", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "date_published", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "downloads", + "type_info": "Int4" + }, + { + "ordinal": 9, + "name": "release_channel", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "featured", + "type_info": "Bool" + }, + { + "ordinal": 11, + "name": "game_versions", + "type_info": "VarcharArray" + }, + { + "ordinal": 12, + "name": "loaders", + "type_info": "VarcharArray" + }, + { + "ordinal": 13, + "name": "files", + "type_info": "TextArray" + }, + { + "ordinal": 14, + "name": "hashes", + "type_info": "TextArray" + } + ], + "parameters": { + "Left": [ + "Int8Array" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + null, + null, + null, + null + ] + } + }, "763eaff18057e579472960e9e8256c22ae275f24a45da96bc3e47385376faae3": { "query": "\n UPDATE mods\n SET downloads = downloads + 1\n WHERE id = $1\n ", "describe": { @@ -1916,44 +2058,6 @@ "nullable": [] } }, - "8eff482abade78aff21f443abf7dedd57e1c91e46bebf1b553db5be505f4bd20": { - "query": "\n SELECT d.joining_platform_id, d.url, dp.short, dp.name FROM mods_donations d\n INNER JOIN donation_platforms dp ON d.joining_platform_id=dp.id\n WHERE joining_mod_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "joining_platform_id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "url", - "type_info": "Varchar" - }, - { - "ordinal": 2, - "name": "short", - "type_info": "Varchar" - }, - { - "ordinal": 3, - "name": "name", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false, - false, - false, - false - ] - } - }, "8f706d78ac4235ea04c59e2c220a4791e1d08fdf287b783b4aaef36fd2445467": { "query": "\n DELETE FROM loaders\n WHERE loader = $1\n ", "describe": { @@ -2393,44 +2497,6 @@ ] } }, - "a28188c4840d0f3449379b3bba6b3c4af9483e01f50fd56785317398a59881ca": { - "query": "\n SELECT files.id, files.url, files.filename, files.is_primary FROM files\n WHERE files.version_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int8" - }, - { - "ordinal": 1, - "name": "url", - "type_info": "Varchar" - }, - { - "ordinal": 2, - "name": "filename", - "type_info": "Varchar" - }, - { - "ordinal": 3, - "name": "is_primary", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false, - false, - false, - false - ] - } - }, "a39ce28b656032f862b205cffa393a76b989f4803654a615477a94fda5f57354": { "query": "\n DELETE FROM states\n WHERE id = $1\n ", "describe": { @@ -2791,80 +2857,6 @@ "nullable": [] } }, - "b8485af7c70d7e585a681bb9733ed7864c49b8e280a0097f32e1edfeae83d08b": { - "query": "\n SELECT v.mod_id, v.author_id, v.name, v.version_number,\n v.changelog, v.changelog_url, v.date_published, v.downloads,\n release_channels.channel, v.featured\n FROM versions v\n INNER JOIN release_channels ON v.release_channel = release_channels.id\n WHERE v.id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "mod_id", - "type_info": "Int8" - }, - { - "ordinal": 1, - "name": "author_id", - "type_info": "Int8" - }, - { - "ordinal": 2, - "name": "name", - "type_info": "Varchar" - }, - { - "ordinal": 3, - "name": "version_number", - "type_info": "Varchar" - }, - { - "ordinal": 4, - "name": "changelog", - "type_info": "Varchar" - }, - { - "ordinal": 5, - "name": "changelog_url", - "type_info": "Varchar" - }, - { - "ordinal": 6, - "name": "date_published", - "type_info": "Timestamptz" - }, - { - "ordinal": 7, - "name": "downloads", - "type_info": "Int4" - }, - { - "ordinal": 8, - "name": "channel", - "type_info": "Varchar" - }, - { - "ordinal": 9, - "name": "featured", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false, - false, - false, - false, - false, - true, - false, - false, - false, - false - ] - } - }, "b903ac4e686ef85ba28d698c668da07860e7f276b261d8f2cebb74e73b094970": { "query": "\n DELETE FROM hashes\n WHERE EXISTS(\n SELECT 1 FROM files WHERE\n (files.version_id = $1) AND\n (hashes.file_id = files.id)\n )\n ", "describe": { @@ -3077,6 +3069,188 @@ ] } }, + "c2e49d3d71b4fe46ad1775311b3fdbd9065675a096921186eff2e2b280874afe": { + "query": "\n SELECT m.id id, m.title title, m.description description, m.downloads downloads,\n m.icon_url icon_url, m.body body, m.body_url body_url, m.published published,\n m.updated updated, m.status status,\n m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,\n m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name,\n ARRAY_AGG( DISTINCT c.category) categories, ARRAY_AGG(DISTINCT v.id) versions, ARRAY_AGG(DISTINCT md.joining_platform_id || ', ' || md.url || ', ' || dp.short || ', ' || dp.name) donations\n FROM mods m\n INNER JOIN mods_categories mc ON joining_mod_id = m.id\n INNER JOIN categories c ON mc.joining_category_id = c.id\n INNER JOIN versions v ON v.mod_id = m.id\n INNER JOIN mods_donations md ON md.joining_mod_id = m.id\n INNER JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n INNER JOIN statuses s ON s.id = m.status\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN licenses l ON m.license = l.id\n WHERE m.id IN (SELECT * FROM UNNEST($1::bigint[]))\n GROUP BY m.id, s.id, cs.id, ss.id, l.id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "downloads", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "icon_url", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "body", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "body_url", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "published", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "updated", + "type_info": "Timestamptz" + }, + { + "ordinal": 9, + "name": "status", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "issues_url", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "source_url", + "type_info": "Varchar" + }, + { + "ordinal": 12, + "name": "wiki_url", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "discord_url", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "license_url", + "type_info": "Varchar" + }, + { + "ordinal": 15, + "name": "team_id", + "type_info": "Int8" + }, + { + "ordinal": 16, + "name": "client_side", + "type_info": "Int4" + }, + { + "ordinal": 17, + "name": "server_side", + "type_info": "Int4" + }, + { + "ordinal": 18, + "name": "license", + "type_info": "Int4" + }, + { + "ordinal": 19, + "name": "slug", + "type_info": "Varchar" + }, + { + "ordinal": 20, + "name": "status_name", + "type_info": "Varchar" + }, + { + "ordinal": 21, + "name": "client_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 22, + "name": "server_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 23, + "name": "short", + "type_info": "Varchar" + }, + { + "ordinal": 24, + "name": "license_name", + "type_info": "Varchar" + }, + { + "ordinal": 25, + "name": "categories", + "type_info": "VarcharArray" + }, + { + "ordinal": 26, + "name": "versions", + "type_info": "Int8Array" + }, + { + "ordinal": 27, + "name": "donations", + "type_info": "TextArray" + } + ], + "parameters": { + "Left": [ + "Int8Array" + ] + }, + "nullable": [ + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + null, + null, + null + ] + } + }, "c545a74e902c5c63bca1057b76e94b9547ee21fadbc61964f45837915d5f4608": { "query": "\n INSERT INTO mods_donations (\n joining_mod_id, joining_platform_id, url\n )\n VALUES (\n $1, $2, $3\n )\n ", "describe": { @@ -3490,52 +3664,6 @@ "nullable": [] } }, - "deb81673526789bca38d39e64303f61d2a63febfdfb68136e58517af9f7792bc": { - "query": "\n SELECT category FROM mods_categories\n INNER JOIN categories ON joining_category_id = id\n WHERE joining_mod_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "category", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false - ] - } - }, - "e2d93718c6f26cf739d25b56b6c5e8c295bb4af7e2b8076d6a3664019b57e01f": { - "query": "\n SELECT short, name FROM licenses\n WHERE id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "short", - "type_info": "Varchar" - }, - { - "ordinal": 1, - "name": "name", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [ - "Int4" - ] - }, - "nullable": [ - false, - false - ] - } - }, "e35fa345b43725309b976efffbc8f9e20a62a5e90a86a82a77b55c39c168d2de": { "query": "\n SELECT id FROM versions\n WHERE mod_id = $1\n ", "describe": { @@ -3754,26 +3882,6 @@ ] } }, - "f0dd4e10e7c5c4c27ee84be6010919a1b23cb9438ff869c1902849874c75a4af": { - "query": "\n SELECT loaders.loader FROM loaders\n INNER JOIN loaders_versions ON loaders.id = loaders_versions.loader_id\n WHERE loaders_versions.version_id = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "loader", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false - ] - } - }, "f12ae54acf02e06e9b8774e8c2ea95058a78f6d724645adcd02f9dea6538024f": { "query": "\n INSERT INTO categories (category)\n VALUES ($1)\n ON CONFLICT (category) DO NOTHING\n RETURNING id\n ", "describe": { diff --git a/src/database/models/mod_item.rs b/src/database/models/mod_item.rs index e7bd44ab5..1cda3d54a 100644 --- a/src/database/models/mod_item.rs +++ b/src/database/models/mod_item.rs @@ -401,108 +401,87 @@ impl Mod { where E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy, { - let result = Self::get(id, executor).await?; - if let Some(inner) = result { - use futures::TryStreamExt; - let categories: Vec = sqlx::query!( - " - SELECT category FROM mods_categories - INNER JOIN categories ON joining_category_id = id - WHERE joining_mod_id = $1 - ", - id as ModId, - ) - .fetch_many(executor) - .try_filter_map(|e| async { Ok(e.right().map(|c| c.category)) }) - .try_collect::>() - .await?; - - let versions: Vec = sqlx::query!( - " - SELECT id FROM versions - WHERE mod_id = $1 - ", - id as ModId, - ) - .fetch_many(executor) - .try_filter_map(|e| async { Ok(e.right().map(|c| VersionId(c.id))) }) - .try_collect::>() - .await?; - - let donations: Vec = sqlx::query!( - " - SELECT d.joining_platform_id, d.url, dp.short, dp.name FROM mods_donations d - INNER JOIN donation_platforms dp ON d.joining_platform_id=dp.id - WHERE joining_mod_id = $1 - ", - id as ModId, - ) - .fetch_many(executor) - .try_filter_map(|e| async { - Ok(e.right().map(|c| DonationUrl { - mod_id: id, - platform_id: DonationPlatformId(c.joining_platform_id), - platform_short: c.short, - platform_name: c.name, - url: c.url, - })) - }) - .try_collect::>() - .await?; - - let status = sqlx::query!( - " - SELECT status FROM statuses - WHERE id = $1 - ", - inner.status.0, - ) - .fetch_one(executor) - .await? - .status; - - let client_side = sqlx::query!( - " - SELECT name FROM side_types - WHERE id = $1 - ", - inner.client_side.0, - ) - .fetch_one(executor) - .await? - .name; - - let server_side = sqlx::query!( - " - SELECT name FROM side_types - WHERE id = $1 - ", - inner.server_side.0, - ) - .fetch_one(executor) - .await? - .name; - - let license = sqlx::query!( - " - SELECT short, name FROM licenses - WHERE id = $1 - ", - inner.license.0, - ) - .fetch_one(executor) + let result = sqlx::query!( + " + SELECT m.id id, m.title title, m.description description, m.downloads downloads, + m.icon_url icon_url, m.body body, m.body_url body_url, m.published published, + m.updated updated, m.status status, + m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url, + m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, + s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, + ARRAY_AGG( DISTINCT c.category) categories, ARRAY_AGG(DISTINCT v.id) versions, ARRAY_AGG(DISTINCT md.joining_platform_id || ', ' || md.url || ', ' || dp.short || ', ' || dp.name) donations + FROM mods m + INNER JOIN mods_categories mc ON joining_mod_id = m.id + INNER JOIN categories c ON mc.joining_category_id = c.id + INNER JOIN versions v ON v.mod_id = m.id + INNER JOIN mods_donations md ON md.joining_mod_id = m.id + INNER JOIN donation_platforms dp ON md.joining_platform_id = dp.id + INNER JOIN statuses s ON s.id = m.status + INNER JOIN side_types cs ON m.client_side = cs.id + INNER JOIN side_types ss ON m.server_side = ss.id + INNER JOIN licenses l ON m.license = l.id + WHERE m.id IN (SELECT * FROM UNNEST($1::bigint[])) + GROUP BY m.id, s.id, cs.id, ss.id, l.id; + ", + id as ModId, + ) + .fetch_optional(executor) .await?; + if let Some(m) = result { Ok(Some(QueryMod { - inner, - categories, - versions, - donation_urls: donations, - status: crate::models::mods::ModStatus::from_str(&status), - license_id: license.short, - license_name: license.name, - client_side: crate::models::mods::SideType::from_str(&client_side), - server_side: crate::models::mods::SideType::from_str(&server_side), + inner: Mod { + id: ModId(m.id.clone()), + team_id: TeamId(m.team_id.clone()), + title: m.title.clone(), + description: m.description.clone(), + downloads: m.downloads.clone(), + body_url: m.body_url.clone(), + icon_url: m.icon_url.clone(), + published: m.published.clone(), + updated: m.updated.clone(), + issues_url: m.issues_url.clone(), + source_url: m.source_url.clone(), + wiki_url: m.wiki_url.clone(), + license_url: m.license_url.clone(), + discord_url: m.discord_url.clone(), + client_side: SideTypeId(m.client_side.clone()), + status: StatusId(m.status.clone()), + server_side: SideTypeId(m.server_side.clone()), + license: LicenseId(m.license.clone()), + slug: m.slug.clone(), + body: m.body.clone(), + }, + categories: m.categories.clone().unwrap_or(vec![]), + versions: m + .versions + .clone() + .unwrap_or(vec![]) + .into_iter() + .map(|v| VersionId(v)) + .collect(), + donation_urls: m + .donations + .clone() + .unwrap_or(vec![]) + .into_iter() + .map(|d| { + // TODO: Change this once SQLX allows postgres tuples + let strings: Vec<&str> = d.split(", ").collect(); + DonationUrl { + mod_id: ModId(m.id.clone()), + platform_id: DonationPlatformId(strings[0].parse().unwrap_or(0)), + platform_short: strings[2].to_string(), + platform_name: strings[3].to_string(), + url: strings[1].to_string(), + } + }) + .collect(), + status: crate::models::mods::ModStatus::from_str(&m.status_name), + license_id: m.short, + license_name: m.license_name, + client_side: crate::models::mods::SideType::from_str(&m.client_side_type), + server_side: crate::models::mods::SideType::from_str(&m.server_side_type), })) } else { Ok(None) @@ -512,19 +491,84 @@ impl Mod { pub async fn get_many_full<'a, E>( mod_ids: Vec, exec: E, - ) -> Result>, sqlx::Error> + ) -> Result, sqlx::Error> where E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy, { - let mut mods = Vec::new(); + use futures::TryStreamExt; - for mod_id in mod_ids { - mods.push(Self::get_full(mod_id, exec).await?) - } - - Ok(mods) - /*// TODO: this could be optimized - futures::future::try_join_all(mod_ids.into_iter().map(|id| Self::get_full(id, exec))).await*/ + let mod_ids_parsed: Vec = mod_ids.into_iter().map(|x| x.0).collect(); + sqlx::query!( + " + SELECT m.id id, m.title title, m.description description, m.downloads downloads, + m.icon_url icon_url, m.body body, m.body_url body_url, m.published published, + m.updated updated, m.status status, + m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url, + m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, + s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, + ARRAY_AGG( DISTINCT c.category) categories, ARRAY_AGG(DISTINCT v.id) versions, ARRAY_AGG(DISTINCT md.joining_platform_id || ', ' || md.url || ', ' || dp.short || ', ' || dp.name) donations + FROM mods m + INNER JOIN mods_categories mc ON joining_mod_id = m.id + INNER JOIN categories c ON mc.joining_category_id = c.id + INNER JOIN versions v ON v.mod_id = m.id + INNER JOIN mods_donations md ON md.joining_mod_id = m.id + INNER JOIN donation_platforms dp ON md.joining_platform_id = dp.id + INNER JOIN statuses s ON s.id = m.status + INNER JOIN side_types cs ON m.client_side = cs.id + INNER JOIN side_types ss ON m.server_side = ss.id + INNER JOIN licenses l ON m.license = l.id + WHERE m.id IN (SELECT * FROM UNNEST($1::bigint[])) + GROUP BY m.id, s.id, cs.id, ss.id, l.id; + ", + &mod_ids_parsed + ) + .fetch_many(exec) + .try_filter_map(|e| async { + Ok(e.right().map(|m| QueryMod { + inner: Mod { + id: ModId(m.id.clone()), + team_id: TeamId(m.team_id.clone()), + title: m.title.clone(), + description: m.description.clone(), + downloads: m.downloads.clone(), + body_url: m.body_url.clone(), + icon_url: m.icon_url.clone(), + published: m.published.clone(), + updated: m.updated.clone(), + issues_url: m.issues_url.clone(), + source_url: m.source_url.clone(), + wiki_url: m.wiki_url.clone(), + license_url: m.license_url.clone(), + discord_url: m.discord_url.clone(), + client_side: SideTypeId(m.client_side.clone()), + status: StatusId(m.status.clone()), + server_side: SideTypeId(m.server_side.clone()), + license: LicenseId(m.license.clone()), + slug: m.slug.clone(), + body: m.body.clone(), + }, + categories: m.categories.clone().unwrap_or(vec![]), + versions: m.versions.clone().unwrap_or(vec![]).into_iter().map(|v| VersionId(v)).collect(), + donation_urls: m.donations.clone().unwrap_or(vec![]).into_iter().map(|d| { + // TODO: Change this once SQLX allows postgres tuples + let strings : Vec<&str> = d.split(", ").collect(); + DonationUrl { + mod_id: ModId(m.id.clone()), + platform_id: DonationPlatformId(strings[0].parse().unwrap_or(0)), + platform_short: strings[2].to_string(), + platform_name: strings[3].to_string(), + url: strings[1].to_string() + } + }).collect(), + status: crate::models::mods::ModStatus::from_str(&m.status_name), + license_id: m.short, + license_name: m.license_name, + client_side: crate::models::mods::SideType::from_str(&m.client_side_type), + server_side: crate::models::mods::SideType::from_str(&m.server_side_type), + })) + }) + .try_collect::>() + .await } } diff --git a/src/database/models/version_item.rs b/src/database/models/version_item.rs index 9f7802cf3..815a26d2b 100644 --- a/src/database/models/version_item.rs +++ b/src/database/models/version_item.rs @@ -1,5 +1,6 @@ use super::ids::*; use super::DatabaseError; +use std::collections::HashMap; pub struct VersionBuilder { pub version_id: VersionId, @@ -461,100 +462,78 @@ impl Version { { let result = sqlx::query!( " - SELECT v.mod_id, v.author_id, v.name, v.version_number, - v.changelog, v.changelog_url, v.date_published, v.downloads, - release_channels.channel, v.featured + 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.changelog_url changelog_url, v.date_published date_published, v.downloads downloads, + rc.channel release_channel, v.featured featured, + ARRAY_AGG(gv.version ORDER BY gv.created) game_versions, ARRAY_AGG(DISTINCT l.loader) loaders, + ARRAY_AGG(DISTINCT f.id || ', ' || f.filename || ', ' || f.is_primary || ', ' || f.url) files, + ARRAY_AGG(DISTINCT h.hash || ', ' || h.algorithm || ', ' || h.file_id) hashes FROM versions v - INNER JOIN release_channels ON v.release_channel = release_channels.id + INNER JOIN release_channels rc on v.release_channel = rc.id + INNER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id + INNER JOIN game_versions gv on gvv.game_version_id = gv.id + INNER JOIN loaders_versions lv on v.id = lv.version_id + INNER JOIN loaders l on lv.loader_id = l.id + INNER JOIN files f on v.id = f.version_id + INNER JOIN hashes h on f.id = h.file_id WHERE v.id = $1 + GROUP BY v.id, rc.id; ", id as VersionId, ) - .fetch_optional(executor) - .await?; - - if let Some(row) = result { - use futures::TryStreamExt; - - let game_versions: Vec = sqlx::query!( - " - SELECT gv.version FROM game_versions_versions gvv - INNER JOIN game_versions gv ON gvv.game_version_id=gv.id - WHERE gvv.joining_version_id = $1 - ORDER BY gv.created - ", - id as VersionId, - ) - .fetch_many(executor) - .try_filter_map(|e| async { Ok(e.right().map(|c| c.version)) }) - .try_collect::>() + .fetch_optional(executor) .await?; - let loaders: Vec = sqlx::query!( - " - SELECT loaders.loader FROM loaders - INNER JOIN loaders_versions ON loaders.id = loaders_versions.loader_id - WHERE loaders_versions.version_id = $1 - ", - id as VersionId, - ) - .fetch_many(executor) - .try_filter_map(|e| async { Ok(e.right().map(|c| c.loader)) }) - .try_collect::>() - .await?; + if let Some(v) = result { + let mut hashes: Vec<(FileId, String, Vec)> = Vec::new(); - let mut files = sqlx::query!( - " - SELECT files.id, files.url, files.filename, files.is_primary FROM files - WHERE files.version_id = $1 - ", - id as VersionId, - ) - .fetch_many(executor) - .try_filter_map(|e| async { - Ok(e.right().map(|c| QueryFile { - id: FileId(c.id), - url: c.url, - filename: c.filename, - hashes: std::collections::HashMap::new(), - primary: c.is_primary, - })) - }) - .try_collect::>() - .await?; - - for file in files.iter_mut() { - let files = sqlx::query!( - " - SELECT hashes.algorithm, hashes.hash FROM hashes - WHERE hashes.file_id = $1 - ", - file.id as FileId - ) - .fetch_many(executor) - .try_filter_map(|e| async { Ok(e.right().map(|c| (c.algorithm, c.hash))) }) - .try_collect::)>>() - .await?; - - file.hashes.extend(files); - } + v.hashes.unwrap_or(vec![]).into_iter().for_each(|f| { + let hash: Vec<&str> = f.split(", ").collect(); + hashes.push(( + FileId(hash[2].parse().unwrap_or(0)), + hash[1].to_string(), + hash[0].to_string().into_bytes(), + )); + }); Ok(Some(QueryVersion { - id, - mod_id: ModId(row.mod_id), - author_id: UserId(row.author_id), - name: row.name, - version_number: row.version_number, - changelog: row.changelog, - changelog_url: row.changelog_url, - date_published: row.date_published, - downloads: row.downloads, + id: VersionId(v.id), + mod_id: ModId(v.mod_id), + author_id: UserId(v.author_id), + name: v.version_name, + version_number: v.version_number, + changelog: v.changelog, + changelog_url: v.changelog_url, + date_published: v.date_published, + downloads: v.downloads, + release_channel: v.release_channel, + files: v + .files + .unwrap_or(vec![]) + .into_iter() + .map(|f| { + let file: Vec<&str> = f.split(", ").collect(); + let file_id = FileId(file[0].parse().unwrap_or(0)); + let mut file_hashes = HashMap::new(); - release_channel: row.channel, - files, - loaders, - game_versions, - featured: row.featured, + for hash in &hashes { + if hash.0 .0 == file_id.0 { + file_hashes.insert(hash.1.clone(), hash.2.clone()); + } + } + + QueryFile { + id: file_id, + url: file[3].to_string(), + filename: file[1].to_string(), + hashes: file_hashes, + primary: file[3].parse().unwrap_or(false), + } + }) + .collect(), + game_versions: v.game_versions.unwrap_or(vec![]), + loaders: v.loaders.unwrap_or(vec![]), + featured: v.featured, })) } else { Ok(None) @@ -564,19 +543,82 @@ impl Version { pub async fn get_many_full<'a, E>( version_ids: Vec, exec: E, - ) -> Result>, sqlx::Error> + ) -> Result, sqlx::Error> where E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy, { - let mut versions = Vec::new(); + use futures::stream::TryStreamExt; - for version_id in version_ids { - versions.push(Self::get_full(version_id, exec).await?) - } + let version_ids_parsed: Vec = version_ids.into_iter().map(|x| x.0).collect(); + sqlx::query!( + " + 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.changelog_url changelog_url, v.date_published date_published, v.downloads downloads, + rc.channel release_channel, v.featured featured, + ARRAY_AGG(gv.version ORDER BY gv.created) game_versions, ARRAY_AGG(DISTINCT l.loader) loaders, + ARRAY_AGG(DISTINCT f.id || ', ' || f.filename || ', ' || f.is_primary || ', ' || f.url) files, + ARRAY_AGG(DISTINCT h.hash || ', ' || h.algorithm || ', ' || h.file_id) hashes + FROM versions v + INNER JOIN release_channels rc on v.release_channel = rc.id + INNER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id + INNER JOIN game_versions gv on gvv.game_version_id = gv.id + INNER JOIN loaders_versions lv on v.id = lv.version_id + INNER JOIN loaders l on lv.loader_id = l.id + INNER JOIN files f on v.id = f.version_id + INNER JOIN hashes h on f.id = h.file_id + WHERE v.id IN (SELECT * FROM UNNEST($1::bigint[])) + GROUP BY v.id, rc.id; + ", + &version_ids_parsed + ) + .fetch_many(exec) + .try_filter_map(|e| async { + Ok(e.right().map(|v| { + let mut hashes : Vec<(FileId, String, Vec)> = Vec::new(); - Ok(versions) - /* futures::future::try_join_all(version_ids.into_iter().map(|id| Self::get_full(id, exec))) - .await*/ + v.hashes.unwrap_or(vec![]).into_iter().for_each(|f| { + let hash : Vec<&str> = f.split(", ").collect(); + hashes.push((FileId(hash[2].parse().unwrap_or(0)), hash[1].to_string(), hash[0].to_string().into_bytes())); + }); + + QueryVersion { + id: VersionId(v.id), + mod_id: ModId(v.mod_id), + author_id: UserId(v.author_id), + name: v.version_name, + version_number: v.version_number, + changelog: v.changelog, + changelog_url: v.changelog_url, + date_published: v.date_published, + downloads: v.downloads, + release_channel: v.release_channel, + files: v.files.unwrap_or(vec![]).into_iter().map(|f| { + let file : Vec<&str> = f.split(", ").collect(); + let file_id = FileId(file[0].parse().unwrap_or(0)); + let mut file_hashes = HashMap::new(); + + for hash in &hashes { + if hash.0.0 == file_id.0 { + file_hashes.insert(hash.1.clone(), hash.2.clone()); + } + } + + QueryFile { + id: file_id, + url: file[3].to_string(), + filename: file[1].to_string(), + hashes: file_hashes, + primary: file[3].parse().unwrap_or(false) + } + }).collect(), + game_versions: v.game_versions.unwrap_or(vec![]), + loaders: v.loaders.unwrap_or(vec![]), + featured: v.featured, + } + })) + }) + .try_collect::>() + .await } } @@ -621,6 +663,6 @@ pub struct QueryFile { pub id: FileId, pub url: String, pub filename: String, - pub hashes: std::collections::HashMap>, + pub hashes: HashMap>, pub primary: bool, } diff --git a/src/routes/mods.rs b/src/routes/mods.rs index f57015008..1107ef548 100644 --- a/src/routes/mods.rs +++ b/src/routes/mods.rs @@ -48,35 +48,33 @@ pub async fn mods_get( let mut mods = Vec::new(); - for mod_data_option in mods_data { - if let Some(mod_data) = mod_data_option { - let mut authorized = !mod_data.status.is_hidden(); + for mod_data in mods_data { + let mut authorized = !mod_data.status.is_hidden(); - if let Some(user) = &user_option { - if !authorized { - if user.role.is_mod() { - authorized = true; - } else { - let user_id: database::models::ids::UserId = user.id.into(); + if let Some(user) = &user_option { + if !authorized { + if user.role.is_mod() { + authorized = true; + } else { + let user_id: database::models::ids::UserId = user.id.into(); - let mod_exists = sqlx::query!( + let mod_exists = sqlx::query!( "SELECT EXISTS(SELECT 1 FROM team_members WHERE team_id = $1 AND user_id = $2)", mod_data.inner.team_id as database::models::ids::TeamId, user_id as database::models::ids::UserId, ) - .fetch_one(&**pool) - .await - .map_err(|e| ApiError::DatabaseError(e.into()))? - .exists; + .fetch_one(&**pool) + .await + .map_err(|e| ApiError::DatabaseError(e.into()))? + .exists; - authorized = mod_exists.unwrap_or(false); - } + authorized = mod_exists.unwrap_or(false); } } + } - if authorized { - mods.push(convert_mod(mod_data)); - } + if authorized { + mods.push(convert_mod(mod_data)); } } diff --git a/src/routes/versions.rs b/src/routes/versions.rs index c499c33d7..33846f1e8 100644 --- a/src/routes/versions.rs +++ b/src/routes/versions.rs @@ -68,9 +68,7 @@ pub async fn versions_get( let mut versions = Vec::new(); for version_data in versions_data { - if let Some(version) = version_data { - versions.push(convert_version(version)); - } + versions.push(convert_version(version_data)); } Ok(HttpResponse::Ok().json(versions)) From 140a8b6804eaee2e25e01cb8610b0b6e14e31a10 Mon Sep 17 00:00:00 2001 From: Geometrically Date: Sun, 24 Jan 2021 22:49:28 -0700 Subject: [PATCH 2/4] Fix docker image build failing --- src/database/models/version_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database/models/version_item.rs b/src/database/models/version_item.rs index 815a26d2b..da739b303 100644 --- a/src/database/models/version_item.rs +++ b/src/database/models/version_item.rs @@ -517,7 +517,7 @@ impl Version { let mut file_hashes = HashMap::new(); for hash in &hashes { - if hash.0 .0 == file_id.0 { + if (hash.0).0 == file_id.0 { file_hashes.insert(hash.1.clone(), hash.2.clone()); } } From fcd548c3137eccf50d72993e2419d48c0c5c43d6 Mon Sep 17 00:00:00 2001 From: Geometrically Date: Mon, 25 Jan 2021 13:00:04 -0700 Subject: [PATCH 3/4] Fix queries not working --- sqlx-data.json | 754 +++++++++++++++++----------- src/database/models/mod_item.rs | 9 +- src/database/models/version_item.rs | 4 +- 3 files changed, 475 insertions(+), 292 deletions(-) diff --git a/sqlx-data.json b/sqlx-data.json index 1cb6399aa..08fc5bc0f 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -471,6 +471,188 @@ "nullable": [] } }, + "1d1ab2b9b33bc9964c0d341385f411d243867a0489706cfb29c0f8689c092bb9": { + "query": "\n SELECT m.id id, m.title title, m.description description, m.downloads downloads,\n m.icon_url icon_url, m.body body, m.body_url body_url, m.published published,\n m.updated updated, m.status status,\n m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,\n m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name,\n ARRAY_AGG( DISTINCT c.category) categories, ARRAY_AGG(DISTINCT v.id) versions,\n ARRAY_AGG( DISTINCT md.joining_platform_id || ', ' || md.url || ', ' || dp.short || ', ' || dp.name) donations\n FROM mods m\n INNER JOIN mods_categories mc ON joining_mod_id = m.id\n INNER JOIN categories c ON mc.joining_category_id = c.id\n INNER JOIN versions v ON v.mod_id = m.id\n LEFT OUTER JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT OUTER JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n INNER JOIN statuses s ON s.id = m.status\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN licenses l ON m.license = l.id\n WHERE m.id IN (SELECT * FROM UNNEST($1::bigint[]))\n GROUP BY m.id, s.id, cs.id, ss.id, l.id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "downloads", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "icon_url", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "body", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "body_url", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "published", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "updated", + "type_info": "Timestamptz" + }, + { + "ordinal": 9, + "name": "status", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "issues_url", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "source_url", + "type_info": "Varchar" + }, + { + "ordinal": 12, + "name": "wiki_url", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "discord_url", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "license_url", + "type_info": "Varchar" + }, + { + "ordinal": 15, + "name": "team_id", + "type_info": "Int8" + }, + { + "ordinal": 16, + "name": "client_side", + "type_info": "Int4" + }, + { + "ordinal": 17, + "name": "server_side", + "type_info": "Int4" + }, + { + "ordinal": 18, + "name": "license", + "type_info": "Int4" + }, + { + "ordinal": 19, + "name": "slug", + "type_info": "Varchar" + }, + { + "ordinal": 20, + "name": "status_name", + "type_info": "Varchar" + }, + { + "ordinal": 21, + "name": "client_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 22, + "name": "server_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 23, + "name": "short", + "type_info": "Varchar" + }, + { + "ordinal": 24, + "name": "license_name", + "type_info": "Varchar" + }, + { + "ordinal": 25, + "name": "categories", + "type_info": "VarcharArray" + }, + { + "ordinal": 26, + "name": "versions", + "type_info": "Int8Array" + }, + { + "ordinal": 27, + "name": "donations", + "type_info": "TextArray" + } + ], + "parameters": { + "Left": [ + "Int8Array" + ] + }, + "nullable": [ + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + null, + null, + null + ] + } + }, "1db6be78a74ff04c52ee105e0df30acf5bbf18f1de328980bb7f3da7f5f6569e": { "query": "\n SELECT id FROM side_types\n WHERE name = $1\n ", "describe": { @@ -1708,110 +1890,6 @@ "nullable": [] } }, - "7562d8fd242d5f73b94e87affffade9b7a4cef2aecc9dce2e45ee7045a59dbd9": { - "query": "\n SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,\n v.changelog changelog, v.changelog_url changelog_url, v.date_published date_published, v.downloads downloads,\n rc.channel release_channel, v.featured featured,\n ARRAY_AGG(gv.version ORDER BY gv.created) game_versions, ARRAY_AGG(DISTINCT l.loader) loaders,\n ARRAY_AGG(DISTINCT f.id || ', ' || f.filename || ', ' || f.is_primary || ', ' || f.url) files,\n ARRAY_AGG(DISTINCT h.hash || ', ' || h.algorithm || ', ' || h.file_id) hashes\n FROM versions v\n INNER JOIN release_channels rc on v.release_channel = rc.id\n INNER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n INNER JOIN game_versions gv on gvv.game_version_id = gv.id\n INNER JOIN loaders_versions lv on v.id = lv.version_id\n INNER JOIN loaders l on lv.loader_id = l.id\n INNER JOIN files f on v.id = f.version_id\n INNER JOIN hashes h on f.id = h.file_id\n WHERE v.id IN (SELECT * FROM UNNEST($1::bigint[]))\n GROUP BY v.id, rc.id;\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int8" - }, - { - "ordinal": 1, - "name": "mod_id", - "type_info": "Int8" - }, - { - "ordinal": 2, - "name": "author_id", - "type_info": "Int8" - }, - { - "ordinal": 3, - "name": "version_name", - "type_info": "Varchar" - }, - { - "ordinal": 4, - "name": "version_number", - "type_info": "Varchar" - }, - { - "ordinal": 5, - "name": "changelog", - "type_info": "Varchar" - }, - { - "ordinal": 6, - "name": "changelog_url", - "type_info": "Varchar" - }, - { - "ordinal": 7, - "name": "date_published", - "type_info": "Timestamptz" - }, - { - "ordinal": 8, - "name": "downloads", - "type_info": "Int4" - }, - { - "ordinal": 9, - "name": "release_channel", - "type_info": "Varchar" - }, - { - "ordinal": 10, - "name": "featured", - "type_info": "Bool" - }, - { - "ordinal": 11, - "name": "game_versions", - "type_info": "VarcharArray" - }, - { - "ordinal": 12, - "name": "loaders", - "type_info": "VarcharArray" - }, - { - "ordinal": 13, - "name": "files", - "type_info": "TextArray" - }, - { - "ordinal": 14, - "name": "hashes", - "type_info": "TextArray" - } - ], - "parameters": { - "Left": [ - "Int8Array" - ] - }, - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - null, - null, - null, - null - ] - } - }, "763eaff18057e579472960e9e8256c22ae275f24a45da96bc3e47385376faae3": { "query": "\n UPDATE mods\n SET downloads = downloads + 1\n WHERE id = $1\n ", "describe": { @@ -1928,6 +2006,110 @@ ] } }, + "8202cfa1d8299c7ae8d204e04ee5d300a786b3bc2b8fe4bb4cdeb4e97d0274d2": { + "query": "\n SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,\n v.changelog changelog, v.changelog_url changelog_url, v.date_published date_published, v.downloads downloads,\n rc.channel release_channel, v.featured featured,\n ARRAY_AGG(gv.version ORDER BY gv.created) game_versions, ARRAY_AGG(DISTINCT l.loader) loaders,\n ARRAY_AGG(DISTINCT f.id || ', ' || f.filename || ', ' || f.is_primary || ', ' || f.url) files,\n ARRAY_AGG(DISTINCT h.algorithm || ', ' || encode(h.hash, 'escape') || ', ' || h.file_id) hashes\n FROM versions v\n INNER JOIN release_channels rc on v.release_channel = rc.id\n INNER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n INNER JOIN game_versions gv on gvv.game_version_id = gv.id\n INNER JOIN loaders_versions lv on v.id = lv.version_id\n INNER JOIN loaders l on lv.loader_id = l.id\n INNER JOIN files f on v.id = f.version_id\n INNER JOIN hashes h on f.id = h.file_id\n WHERE v.id IN (SELECT * FROM UNNEST($1::bigint[]))\n GROUP BY v.id, rc.id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "mod_id", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "author_id", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "version_name", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "version_number", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "changelog", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "changelog_url", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "date_published", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "downloads", + "type_info": "Int4" + }, + { + "ordinal": 9, + "name": "release_channel", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "featured", + "type_info": "Bool" + }, + { + "ordinal": 11, + "name": "game_versions", + "type_info": "VarcharArray" + }, + { + "ordinal": 12, + "name": "loaders", + "type_info": "VarcharArray" + }, + { + "ordinal": 13, + "name": "files", + "type_info": "TextArray" + }, + { + "ordinal": 14, + "name": "hashes", + "type_info": "TextArray" + } + ], + "parameters": { + "Left": [ + "Int8Array" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + null, + null, + null, + null + ] + } + }, "82515e4e7e88f1193c956f032caabc70f535f925e212de30f974afd3ec126092": { "query": "\n INSERT INTO licenses (short, name)\n VALUES ($1, $2)\n ON CONFLICT (short) DO NOTHING\n RETURNING id\n ", "describe": { @@ -3069,188 +3251,6 @@ ] } }, - "c2e49d3d71b4fe46ad1775311b3fdbd9065675a096921186eff2e2b280874afe": { - "query": "\n SELECT m.id id, m.title title, m.description description, m.downloads downloads,\n m.icon_url icon_url, m.body body, m.body_url body_url, m.published published,\n m.updated updated, m.status status,\n m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,\n m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name,\n ARRAY_AGG( DISTINCT c.category) categories, ARRAY_AGG(DISTINCT v.id) versions, ARRAY_AGG(DISTINCT md.joining_platform_id || ', ' || md.url || ', ' || dp.short || ', ' || dp.name) donations\n FROM mods m\n INNER JOIN mods_categories mc ON joining_mod_id = m.id\n INNER JOIN categories c ON mc.joining_category_id = c.id\n INNER JOIN versions v ON v.mod_id = m.id\n INNER JOIN mods_donations md ON md.joining_mod_id = m.id\n INNER JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n INNER JOIN statuses s ON s.id = m.status\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN licenses l ON m.license = l.id\n WHERE m.id IN (SELECT * FROM UNNEST($1::bigint[]))\n GROUP BY m.id, s.id, cs.id, ss.id, l.id;\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int8" - }, - { - "ordinal": 1, - "name": "title", - "type_info": "Varchar" - }, - { - "ordinal": 2, - "name": "description", - "type_info": "Varchar" - }, - { - "ordinal": 3, - "name": "downloads", - "type_info": "Int4" - }, - { - "ordinal": 4, - "name": "icon_url", - "type_info": "Varchar" - }, - { - "ordinal": 5, - "name": "body", - "type_info": "Varchar" - }, - { - "ordinal": 6, - "name": "body_url", - "type_info": "Varchar" - }, - { - "ordinal": 7, - "name": "published", - "type_info": "Timestamptz" - }, - { - "ordinal": 8, - "name": "updated", - "type_info": "Timestamptz" - }, - { - "ordinal": 9, - "name": "status", - "type_info": "Int4" - }, - { - "ordinal": 10, - "name": "issues_url", - "type_info": "Varchar" - }, - { - "ordinal": 11, - "name": "source_url", - "type_info": "Varchar" - }, - { - "ordinal": 12, - "name": "wiki_url", - "type_info": "Varchar" - }, - { - "ordinal": 13, - "name": "discord_url", - "type_info": "Varchar" - }, - { - "ordinal": 14, - "name": "license_url", - "type_info": "Varchar" - }, - { - "ordinal": 15, - "name": "team_id", - "type_info": "Int8" - }, - { - "ordinal": 16, - "name": "client_side", - "type_info": "Int4" - }, - { - "ordinal": 17, - "name": "server_side", - "type_info": "Int4" - }, - { - "ordinal": 18, - "name": "license", - "type_info": "Int4" - }, - { - "ordinal": 19, - "name": "slug", - "type_info": "Varchar" - }, - { - "ordinal": 20, - "name": "status_name", - "type_info": "Varchar" - }, - { - "ordinal": 21, - "name": "client_side_type", - "type_info": "Varchar" - }, - { - "ordinal": 22, - "name": "server_side_type", - "type_info": "Varchar" - }, - { - "ordinal": 23, - "name": "short", - "type_info": "Varchar" - }, - { - "ordinal": 24, - "name": "license_name", - "type_info": "Varchar" - }, - { - "ordinal": 25, - "name": "categories", - "type_info": "VarcharArray" - }, - { - "ordinal": 26, - "name": "versions", - "type_info": "Int8Array" - }, - { - "ordinal": 27, - "name": "donations", - "type_info": "TextArray" - } - ], - "parameters": { - "Left": [ - "Int8Array" - ] - }, - "nullable": [ - false, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - null, - null, - null - ] - } - }, "c545a74e902c5c63bca1057b76e94b9547ee21fadbc61964f45837915d5f4608": { "query": "\n INSERT INTO mods_donations (\n joining_mod_id, joining_platform_id, url\n )\n VALUES (\n $1, $2, $3\n )\n ", "describe": { @@ -3977,6 +3977,188 @@ "nullable": [] } }, + "f4e16c3b62a9bc1a41ee4236e3e134ebc942d92199e8a4bb8d4b8692043de399": { + "query": "\n SELECT m.id id, m.title title, m.description description, m.downloads downloads,\n m.icon_url icon_url, m.body body, m.body_url body_url, m.published published,\n m.updated updated, m.status status,\n m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,\n m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name,\n ARRAY_AGG( DISTINCT c.category) categories, ARRAY_AGG(DISTINCT v.id) versions, ARRAY_AGG(DISTINCT md.joining_platform_id || ', ' || md.url || ', ' || dp.short || ', ' || dp.name) donations\n FROM mods m\n INNER JOIN mods_categories mc ON joining_mod_id = m.id\n INNER JOIN categories c ON mc.joining_category_id = c.id\n INNER JOIN versions v ON v.mod_id = m.id\n INNER JOIN mods_donations md ON md.joining_mod_id = m.id\n INNER JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n INNER JOIN statuses s ON s.id = m.status\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN licenses l ON m.license = l.id\n WHERE m.id = $1\n GROUP BY m.id, s.id, cs.id, ss.id, l.id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "downloads", + "type_info": "Int4" + }, + { + "ordinal": 4, + "name": "icon_url", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "body", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "body_url", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "published", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "updated", + "type_info": "Timestamptz" + }, + { + "ordinal": 9, + "name": "status", + "type_info": "Int4" + }, + { + "ordinal": 10, + "name": "issues_url", + "type_info": "Varchar" + }, + { + "ordinal": 11, + "name": "source_url", + "type_info": "Varchar" + }, + { + "ordinal": 12, + "name": "wiki_url", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "discord_url", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "license_url", + "type_info": "Varchar" + }, + { + "ordinal": 15, + "name": "team_id", + "type_info": "Int8" + }, + { + "ordinal": 16, + "name": "client_side", + "type_info": "Int4" + }, + { + "ordinal": 17, + "name": "server_side", + "type_info": "Int4" + }, + { + "ordinal": 18, + "name": "license", + "type_info": "Int4" + }, + { + "ordinal": 19, + "name": "slug", + "type_info": "Varchar" + }, + { + "ordinal": 20, + "name": "status_name", + "type_info": "Varchar" + }, + { + "ordinal": 21, + "name": "client_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 22, + "name": "server_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 23, + "name": "short", + "type_info": "Varchar" + }, + { + "ordinal": 24, + "name": "license_name", + "type_info": "Varchar" + }, + { + "ordinal": 25, + "name": "categories", + "type_info": "VarcharArray" + }, + { + "ordinal": 26, + "name": "versions", + "type_info": "Int8Array" + }, + { + "ordinal": 27, + "name": "donations", + "type_info": "TextArray" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + null, + null, + null + ] + } + }, "f7bea04e8e279e27a24de1bdf3c413daa8677994df5131494b28691ed6611efc": { "query": "\n SELECT url,expires FROM states\n WHERE id = $1\n ", "describe": { diff --git a/src/database/models/mod_item.rs b/src/database/models/mod_item.rs index 1cda3d54a..86a552f7b 100644 --- a/src/database/models/mod_item.rs +++ b/src/database/models/mod_item.rs @@ -420,7 +420,7 @@ impl Mod { INNER JOIN side_types cs ON m.client_side = cs.id INNER JOIN side_types ss ON m.server_side = ss.id INNER JOIN licenses l ON m.license = l.id - WHERE m.id IN (SELECT * FROM UNNEST($1::bigint[])) + WHERE m.id = $1 GROUP BY m.id, s.id, cs.id, ss.id, l.id; ", id as ModId, @@ -506,13 +506,14 @@ impl Mod { m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url, m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, - ARRAY_AGG( DISTINCT c.category) categories, ARRAY_AGG(DISTINCT v.id) versions, ARRAY_AGG(DISTINCT md.joining_platform_id || ', ' || md.url || ', ' || dp.short || ', ' || dp.name) donations + ARRAY_AGG( DISTINCT c.category) categories, ARRAY_AGG(DISTINCT v.id) versions, + ARRAY_AGG( DISTINCT md.joining_platform_id || ', ' || md.url || ', ' || dp.short || ', ' || dp.name) donations FROM mods m INNER JOIN mods_categories mc ON joining_mod_id = m.id INNER JOIN categories c ON mc.joining_category_id = c.id INNER JOIN versions v ON v.mod_id = m.id - INNER JOIN mods_donations md ON md.joining_mod_id = m.id - INNER JOIN donation_platforms dp ON md.joining_platform_id = dp.id + LEFT OUTER JOIN mods_donations md ON md.joining_mod_id = m.id + LEFT OUTER JOIN donation_platforms dp ON md.joining_platform_id = dp.id INNER JOIN statuses s ON s.id = m.status INNER JOIN side_types cs ON m.client_side = cs.id INNER JOIN side_types ss ON m.server_side = ss.id diff --git a/src/database/models/version_item.rs b/src/database/models/version_item.rs index da739b303..8c9d8ad1f 100644 --- a/src/database/models/version_item.rs +++ b/src/database/models/version_item.rs @@ -557,7 +557,7 @@ impl Version { rc.channel release_channel, v.featured featured, ARRAY_AGG(gv.version ORDER BY gv.created) game_versions, ARRAY_AGG(DISTINCT l.loader) loaders, ARRAY_AGG(DISTINCT f.id || ', ' || f.filename || ', ' || f.is_primary || ', ' || f.url) files, - ARRAY_AGG(DISTINCT h.hash || ', ' || h.algorithm || ', ' || h.file_id) hashes + ARRAY_AGG(DISTINCT h.algorithm || ', ' || encode(h.hash, 'escape') || ', ' || h.file_id) hashes FROM versions v INNER JOIN release_channels rc on v.release_channel = rc.id INNER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id @@ -578,7 +578,7 @@ impl Version { v.hashes.unwrap_or(vec![]).into_iter().for_each(|f| { let hash : Vec<&str> = f.split(", ").collect(); - hashes.push((FileId(hash[2].parse().unwrap_or(0)), hash[1].to_string(), hash[0].to_string().into_bytes())); + hashes.push((FileId(hash[2].parse().unwrap_or(0)), hash[0].to_string(), hash[1].to_string().into_bytes())); }); QueryVersion { From 269884d9f3389542895ccff30c364ad8fb5e35e5 Mon Sep 17 00:00:00 2001 From: Geometrically Date: Mon, 25 Jan 2021 13:15:32 -0700 Subject: [PATCH 4/4] Fix docker build failing --- src/database/models/version_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database/models/version_item.rs b/src/database/models/version_item.rs index 8c9d8ad1f..1e449196b 100644 --- a/src/database/models/version_item.rs +++ b/src/database/models/version_item.rs @@ -598,7 +598,7 @@ impl Version { let mut file_hashes = HashMap::new(); for hash in &hashes { - if hash.0.0 == file_id.0 { + if (hash.0).0 == file_id.0 { file_hashes.insert(hash.1.clone(), hash.2.clone()); } }