diff --git a/sqlx-data.json b/sqlx-data.json index eee0d5276..f05e23874 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -272,18 +272,6 @@ ] } }, - "0dd7a3496dbd56f37640f46ff0575668fe75971aee32d0c5b1b24c35cd3b0861": { - "query": "UPDATE mods\n SET downloads = downloads + 1\n WHERE (id = $1)", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - } - }, "0f29bb5ba767ebd0669c860994e48e3cb2674f0d53f6c4ab85c79d46b04cbb40": { "query": "\n SELECT EXISTS(SELECT 1 FROM mods WHERE id=$1)\n ", "describe": { @@ -528,18 +516,6 @@ "nullable": [] } }, - "1ba3b85bbdb0dd2360d6d18d3931ad1274d2d303601c5ee1b7dae2ba3e316658": { - "query": "UPDATE versions\n SET downloads = downloads + 1\n WHERE (id = $1)", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - } - }, "1c7b0eb4341af5a7942e52f632cf582561f10b4b6a41a082fb8a60f04ac17c6e": { "query": "SELECT EXISTS(SELECT 1 FROM states WHERE id=$1)", "describe": { @@ -1181,6 +1157,18 @@ ] } }, + "49a5d21a1454afc6383b78e468fd0decc75b9163e7286f34ceab22d563a0d3f7": { + "query": "UPDATE mods\n SET downloads = downloads + 1\n WHERE (id = $1)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + } + }, "4a4b4166248877eefcd63603945fdcd392f76812bdec7c70f8ffeb06ee7e737f": { "query": "\n SELECT m.id FROM mods m\n INNER JOIN team_members tm ON tm.team_id = m.team_id\n WHERE tm.user_id = $1 AND tm.role = $2\n ", "describe": { @@ -1301,6 +1289,18 @@ ] } }, + "4d54032b02c860f4facec39eacb4548a0701d4505e7a80b4834650696df69c2b": { + "query": "UPDATE versions\n SET downloads = downloads + 1\n WHERE (id = $1)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + } + }, "4d752ee3f43a1bf34d71c4391c9232537e0941294951f383ea8fa61e9d83fc96": { "query": "\n DELETE FROM mods_gallery\n WHERE id = $1\n ", "describe": { @@ -1313,6 +1313,116 @@ "nullable": [] } }, + "4e40451ec96cf4fa3a806fc71ffa953c087457e3778c25c30dcd664b04e496c6": { + "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 v.version_type version_type, v.featured featured,\n STRING_AGG(DISTINCT gv.version, ' ~~~~ ') game_versions, STRING_AGG(DISTINCT l.loader, ' ~~~~ ') loaders,\n STRING_AGG(DISTINCT f.id || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url || ' |||| ' || f.filename, ' ~~~~ ') files,\n STRING_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id, ' ~~~~ ') hashes,\n STRING_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || d.dependency_type || ' |||| ' || COALESCE(d.dependency_file_name, ' '), ' ~~~~ ') dependencies\n FROM versions v\n LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv on v.id = lv.version_id\n LEFT OUTER JOIN loaders l on lv.loader_id = l.id\n LEFT OUTER JOIN files f on v.id = f.version_id\n LEFT OUTER JOIN hashes h on f.id = h.file_id\n LEFT OUTER JOIN dependencies d on v.id = d.dependent_id\n WHERE v.id = ANY($1)\n GROUP BY v.id\n ORDER BY v.date_published ASC;\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": "version_type", + "type_info": "Varchar" + }, + { + "ordinal": 10, + "name": "featured", + "type_info": "Bool" + }, + { + "ordinal": 11, + "name": "game_versions", + "type_info": "Text" + }, + { + "ordinal": 12, + "name": "loaders", + "type_info": "Text" + }, + { + "ordinal": 13, + "name": "files", + "type_info": "Text" + }, + { + "ordinal": 14, + "name": "hashes", + "type_info": "Text" + }, + { + "ordinal": 15, + "name": "dependencies", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int8Array" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + null, + null, + null, + null, + null + ] + } + }, "4e9f9eafbfd705dfc94571018cb747245a98ea61bad3fae4b3ce284229d99955": { "query": "\n UPDATE mods\n SET description = $1\n WHERE (id = $2)\n ", "describe": { @@ -1792,116 +1902,6 @@ "nullable": [] } }, - "5ed947341b512407530f2d6c0687d0cfc8daa2ad24fbd2e2a9ad6a2c1d226456": { - "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 v.version_type version_type, v.featured featured,\n STRING_AGG(DISTINCT gv.version, ' ~~~~ ') game_versions, STRING_AGG(DISTINCT l.loader, ' ~~~~ ') loaders,\n STRING_AGG(DISTINCT f.id || ' |||| ' || f.filename || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url, ' ~~~~ ') files,\n STRING_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id, ' ~~~~ ') hashes,\n STRING_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || COALESCE(d.dependency_file_name, ' ') || ' |||| ' || d.dependency_type, ' ~~~~ ') dependencies\n FROM versions v\n LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv on v.id = lv.version_id\n LEFT OUTER JOIN loaders l on lv.loader_id = l.id\n LEFT OUTER JOIN files f on v.id = f.version_id\n LEFT OUTER JOIN hashes h on f.id = h.file_id\n LEFT OUTER JOIN dependencies d on v.id = d.dependent_id\n WHERE v.id = $1\n GROUP BY v.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": "version_type", - "type_info": "Varchar" - }, - { - "ordinal": 10, - "name": "featured", - "type_info": "Bool" - }, - { - "ordinal": 11, - "name": "game_versions", - "type_info": "Text" - }, - { - "ordinal": 12, - "name": "loaders", - "type_info": "Text" - }, - { - "ordinal": 13, - "name": "files", - "type_info": "Text" - }, - { - "ordinal": 14, - "name": "hashes", - "type_info": "Text" - }, - { - "ordinal": 15, - "name": "dependencies", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - null, - null, - null, - null, - null - ] - } - }, "5ee2dc5cda9bfc0395da5a4ebf234093e9b8135db5e4a0258b00fa16fb825faa": { "query": "\n SELECT name FROM project_types\n ", "describe": { @@ -2022,8 +2022,8 @@ ] } }, - "63bf0b49bbc5133d34f69348a16e51fe9a7dba338c232ca2d047e2ba221c3713": { - "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 v.version_type version_type, v.featured featured,\n STRING_AGG(DISTINCT gv.version, ' ~~~~ ') game_versions, STRING_AGG(DISTINCT l.loader, ' ~~~~ ') loaders,\n STRING_AGG(DISTINCT f.id || ' |||| ' || f.filename || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url, ' ~~~~ ') files,\n STRING_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id, ' ~~~~ ') hashes,\n STRING_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || COALESCE(d.dependency_file_name, ' ') || ' |||| ' || d.dependency_type, ' ~~~~ ') dependencies\n FROM versions v\n LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv on v.id = lv.version_id\n LEFT OUTER JOIN loaders l on lv.loader_id = l.id\n LEFT OUTER JOIN files f on v.id = f.version_id\n LEFT OUTER JOIN hashes h on f.id = h.file_id\n LEFT OUTER JOIN dependencies d on v.id = d.dependent_id\n WHERE v.id = ANY($1)\n GROUP BY v.id\n ORDER BY v.date_published ASC;\n ", + "62ebb6f33a26f05f28b3d175ef19cb247c7c7f1ac0fce2fae15e6787b33a1b96": { + "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 v.version_type version_type, v.featured featured,\n STRING_AGG(DISTINCT gv.version, ' ~~~~ ') game_versions, STRING_AGG(DISTINCT l.loader, ' ~~~~ ') loaders,\n STRING_AGG(DISTINCT f.id || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url || ' |||| ' || f.filename, ' ~~~~ ') files,\n STRING_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id, ' ~~~~ ') hashes,\n STRING_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || d.dependency_type || ' |||| ' || COALESCE(d.dependency_file_name, ' '), ' ~~~~ ') dependencies\n FROM versions v\n LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv on v.id = lv.version_id\n LEFT OUTER JOIN loaders l on lv.loader_id = l.id\n LEFT OUTER JOIN files f on v.id = f.version_id\n LEFT OUTER JOIN hashes h on f.id = h.file_id\n LEFT OUTER JOIN dependencies d on v.id = d.dependent_id\n WHERE v.id = $1\n GROUP BY v.id;\n ", "describe": { "columns": [ { @@ -2109,7 +2109,7 @@ ], "parameters": { "Left": [ - "Int8Array" + "Int8" ] }, "nullable": [ @@ -2178,6 +2178,442 @@ ] } }, + "690aaaefb15196c0b9b9a79fd819ffb7160b559e5703e11ccea3990bc96e6e5c": { + "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\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, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, pt.name project_type_name,\n STRING_AGG(DISTINCT c.category, ' ~~~~ ') categories, STRING_AGG(DISTINCT v.id::text, ' ~~~~ ') versions,\n STRING_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || mg.created || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' '), ' ~~~~ ') gallery,\n STRING_AGG(DISTINCT md.joining_platform_id || ' |||| ' || dp.short || ' |||| ' || dp.name || ' |||| ' || md.url, ' ~~~~ ') donations\n FROM mods m\n INNER JOIN project_types pt ON pt.id = m.project_type\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 LEFT JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id\n LEFT JOIN categories c ON mc.joining_category_id = c.id\n LEFT JOIN versions v ON v.mod_id = m.id\n LEFT JOIN mods_gallery mg ON mg.mod_id = m.id\n WHERE m.id = $1\n GROUP BY pt.id, s.id, cs.id, ss.id, l.id, m.id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "project_type", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "description", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "downloads", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "follows", + "type_info": "Int4" + }, + { + "ordinal": 6, + "name": "icon_url", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "body", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "body_url", + "type_info": "Varchar" + }, + { + "ordinal": 9, + "name": "published", + "type_info": "Timestamptz" + }, + { + "ordinal": 10, + "name": "updated", + "type_info": "Timestamptz" + }, + { + "ordinal": 11, + "name": "status", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "issues_url", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "source_url", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "wiki_url", + "type_info": "Varchar" + }, + { + "ordinal": 15, + "name": "discord_url", + "type_info": "Varchar" + }, + { + "ordinal": 16, + "name": "license_url", + "type_info": "Varchar" + }, + { + "ordinal": 17, + "name": "team_id", + "type_info": "Int8" + }, + { + "ordinal": 18, + "name": "client_side", + "type_info": "Int4" + }, + { + "ordinal": 19, + "name": "server_side", + "type_info": "Int4" + }, + { + "ordinal": 20, + "name": "license", + "type_info": "Int4" + }, + { + "ordinal": 21, + "name": "slug", + "type_info": "Varchar" + }, + { + "ordinal": 22, + "name": "moderation_message", + "type_info": "Varchar" + }, + { + "ordinal": 23, + "name": "moderation_message_body", + "type_info": "Varchar" + }, + { + "ordinal": 24, + "name": "status_name", + "type_info": "Varchar" + }, + { + "ordinal": 25, + "name": "client_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 26, + "name": "server_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 27, + "name": "short", + "type_info": "Varchar" + }, + { + "ordinal": 28, + "name": "license_name", + "type_info": "Varchar" + }, + { + "ordinal": 29, + "name": "project_type_name", + "type_info": "Varchar" + }, + { + "ordinal": 30, + "name": "categories", + "type_info": "Text" + }, + { + "ordinal": 31, + "name": "versions", + "type_info": "Text" + }, + { + "ordinal": 32, + "name": "gallery", + "type_info": "Text" + }, + { + "ordinal": 33, + "name": "donations", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + null, + null, + null, + null + ] + } + }, + "6915fae5046160623c92ffab1de2dfebf976dc6a3d9fa579c3c1fde75bd854ed": { + "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\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, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, pt.name project_type_name,\n STRING_AGG(DISTINCT c.category, ' ~~~~ ') categories, STRING_AGG(DISTINCT v.id::text, ' ~~~~ ') versions,\n STRING_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || mg.created || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' '), ' ~~~~ ') gallery,\n STRING_AGG(DISTINCT md.joining_platform_id || ' |||| ' || dp.short || ' |||| ' || dp.name || ' |||| ' || md.url, ' ~~~~ ') donations\n FROM mods m\n INNER JOIN project_types pt ON pt.id = m.project_type\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 LEFT JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id\n LEFT JOIN categories c ON mc.joining_category_id = c.id\n LEFT JOIN versions v ON v.mod_id = m.id\n LEFT JOIN mods_gallery mg ON mg.mod_id = m.id\n WHERE m.id = ANY($1)\n GROUP BY pt.id, s.id, cs.id, ss.id, l.id, m.id;\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "project_type", + "type_info": "Int4" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "description", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "downloads", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "follows", + "type_info": "Int4" + }, + { + "ordinal": 6, + "name": "icon_url", + "type_info": "Varchar" + }, + { + "ordinal": 7, + "name": "body", + "type_info": "Varchar" + }, + { + "ordinal": 8, + "name": "body_url", + "type_info": "Varchar" + }, + { + "ordinal": 9, + "name": "published", + "type_info": "Timestamptz" + }, + { + "ordinal": 10, + "name": "updated", + "type_info": "Timestamptz" + }, + { + "ordinal": 11, + "name": "status", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "issues_url", + "type_info": "Varchar" + }, + { + "ordinal": 13, + "name": "source_url", + "type_info": "Varchar" + }, + { + "ordinal": 14, + "name": "wiki_url", + "type_info": "Varchar" + }, + { + "ordinal": 15, + "name": "discord_url", + "type_info": "Varchar" + }, + { + "ordinal": 16, + "name": "license_url", + "type_info": "Varchar" + }, + { + "ordinal": 17, + "name": "team_id", + "type_info": "Int8" + }, + { + "ordinal": 18, + "name": "client_side", + "type_info": "Int4" + }, + { + "ordinal": 19, + "name": "server_side", + "type_info": "Int4" + }, + { + "ordinal": 20, + "name": "license", + "type_info": "Int4" + }, + { + "ordinal": 21, + "name": "slug", + "type_info": "Varchar" + }, + { + "ordinal": 22, + "name": "moderation_message", + "type_info": "Varchar" + }, + { + "ordinal": 23, + "name": "moderation_message_body", + "type_info": "Varchar" + }, + { + "ordinal": 24, + "name": "status_name", + "type_info": "Varchar" + }, + { + "ordinal": 25, + "name": "client_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 26, + "name": "server_side_type", + "type_info": "Varchar" + }, + { + "ordinal": 27, + "name": "short", + "type_info": "Varchar" + }, + { + "ordinal": 28, + "name": "license_name", + "type_info": "Varchar" + }, + { + "ordinal": 29, + "name": "project_type_name", + "type_info": "Varchar" + }, + { + "ordinal": 30, + "name": "categories", + "type_info": "Text" + }, + { + "ordinal": 31, + "name": "versions", + "type_info": "Text" + }, + { + "ordinal": 32, + "name": "gallery", + "type_info": "Text" + }, + { + "ordinal": 33, + "name": "donations", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int8Array" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + null, + null, + null, + null + ] + } + }, "6a7b7704c2a0c52a70f5d881a1e6d3e8e77ddaa83ecc5688cd86bf327775fb76": { "query": "\n SELECT f.id id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n WHERE h.algorithm = $2 AND h.hash = $1\n ", "describe": { @@ -3088,224 +3524,6 @@ ] } }, - "97c21dc36e62b0e94f63e76a0e2bd87357f192531c4eeb5678549d8607a4a0bc": { - "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\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, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, pt.name project_type_name,\n STRING_AGG(DISTINCT c.category, ' ~~~~ ') categories, STRING_AGG(DISTINCT v.id::text, ' ~~~~ ') versions,\n STRING_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' ') || ' |||| ' || mg.created, ' ~~~~ ') gallery,\n STRING_AGG(DISTINCT md.joining_platform_id || ' |||| ' || md.url || ' |||| ' || dp.short || ' |||| ' || dp.name, ' ~~~~ ') donations\n FROM mods m\n INNER JOIN project_types pt ON pt.id = m.project_type\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 LEFT JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id\n LEFT JOIN categories c ON mc.joining_category_id = c.id\n LEFT JOIN versions v ON v.mod_id = m.id\n LEFT JOIN mods_gallery mg ON mg.mod_id = m.id\n WHERE m.id = $1\n GROUP BY pt.id, s.id, cs.id, ss.id, l.id, m.id;\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int8" - }, - { - "ordinal": 1, - "name": "project_type", - "type_info": "Int4" - }, - { - "ordinal": 2, - "name": "title", - "type_info": "Varchar" - }, - { - "ordinal": 3, - "name": "description", - "type_info": "Varchar" - }, - { - "ordinal": 4, - "name": "downloads", - "type_info": "Int4" - }, - { - "ordinal": 5, - "name": "follows", - "type_info": "Int4" - }, - { - "ordinal": 6, - "name": "icon_url", - "type_info": "Varchar" - }, - { - "ordinal": 7, - "name": "body", - "type_info": "Varchar" - }, - { - "ordinal": 8, - "name": "body_url", - "type_info": "Varchar" - }, - { - "ordinal": 9, - "name": "published", - "type_info": "Timestamptz" - }, - { - "ordinal": 10, - "name": "updated", - "type_info": "Timestamptz" - }, - { - "ordinal": 11, - "name": "status", - "type_info": "Int4" - }, - { - "ordinal": 12, - "name": "issues_url", - "type_info": "Varchar" - }, - { - "ordinal": 13, - "name": "source_url", - "type_info": "Varchar" - }, - { - "ordinal": 14, - "name": "wiki_url", - "type_info": "Varchar" - }, - { - "ordinal": 15, - "name": "discord_url", - "type_info": "Varchar" - }, - { - "ordinal": 16, - "name": "license_url", - "type_info": "Varchar" - }, - { - "ordinal": 17, - "name": "team_id", - "type_info": "Int8" - }, - { - "ordinal": 18, - "name": "client_side", - "type_info": "Int4" - }, - { - "ordinal": 19, - "name": "server_side", - "type_info": "Int4" - }, - { - "ordinal": 20, - "name": "license", - "type_info": "Int4" - }, - { - "ordinal": 21, - "name": "slug", - "type_info": "Varchar" - }, - { - "ordinal": 22, - "name": "moderation_message", - "type_info": "Varchar" - }, - { - "ordinal": 23, - "name": "moderation_message_body", - "type_info": "Varchar" - }, - { - "ordinal": 24, - "name": "status_name", - "type_info": "Varchar" - }, - { - "ordinal": 25, - "name": "client_side_type", - "type_info": "Varchar" - }, - { - "ordinal": 26, - "name": "server_side_type", - "type_info": "Varchar" - }, - { - "ordinal": 27, - "name": "short", - "type_info": "Varchar" - }, - { - "ordinal": 28, - "name": "license_name", - "type_info": "Varchar" - }, - { - "ordinal": 29, - "name": "project_type_name", - "type_info": "Varchar" - }, - { - "ordinal": 30, - "name": "categories", - "type_info": "Text" - }, - { - "ordinal": 31, - "name": "versions", - "type_info": "Text" - }, - { - "ordinal": 32, - "name": "gallery", - "type_info": "Text" - }, - { - "ordinal": 33, - "name": "donations", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - null, - null, - null, - null - ] - } - }, "98653aee768ce2e5493178a89acfe377a9bab715d8b1e612883690d45b676123": { "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\n m.icon_url icon_url, m.published published,\n m.updated updated,\n m.team_id team_id, m.license license, m.slug slug,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, pt.name project_type_name, u.username username,\n STRING_AGG(DISTINCT c.category, ',') categories, STRING_AGG(DISTINCT lo.loader, ',') loaders, STRING_AGG(DISTINCT gv.version, ',') versions,\n STRING_AGG(DISTINCT mg.image_url, ',') gallery\n FROM mods m\n LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id\n LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id\n LEFT OUTER JOIN versions v ON v.mod_id = m.id\n LEFT OUTER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id\n LEFT OUTER JOIN game_versions gv ON gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv ON lv.version_id = v.id\n LEFT OUTER JOIN loaders lo ON lo.id = lv.loader_id\n LEFT OUTER JOIN mods_gallery mg ON mg.mod_id = m.id\n INNER JOIN statuses s ON s.id = m.status\n INNER JOIN project_types pt ON pt.id = m.project_type\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 INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.role = $2 AND tm.accepted = TRUE\n INNER JOIN users u ON tm.user_id = u.id\n WHERE s.status = $1\n GROUP BY m.id, s.id, cs.id, ss.id, l.id, pt.id, u.id;\n ", "describe": { @@ -3860,224 +4078,6 @@ ] } }, - "aafbe87cb07227b382130f4f9b0ce2220972c14adf070c31010fd1623ceffdd3": { - "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\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, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,\n s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, pt.name project_type_name,\n STRING_AGG(DISTINCT c.category, ' ~~~~ ') categories, STRING_AGG(DISTINCT v.id::text, ' ~~~~ ') versions,\n STRING_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' ') || ' |||| ' || mg.created, ' ~~~~ ') gallery,\n STRING_AGG(DISTINCT md.joining_platform_id || ' |||| ' || md.url || ' |||| ' || dp.short || ' |||| ' || dp.name, ' ~~~~ ') donations\n FROM mods m\n INNER JOIN project_types pt ON pt.id = m.project_type\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 LEFT JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id\n LEFT JOIN categories c ON mc.joining_category_id = c.id\n LEFT JOIN versions v ON v.mod_id = m.id\n LEFT JOIN mods_gallery mg ON mg.mod_id = m.id\n WHERE m.id = ANY($1)\n GROUP BY pt.id, s.id, cs.id, ss.id, l.id, m.id;\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int8" - }, - { - "ordinal": 1, - "name": "project_type", - "type_info": "Int4" - }, - { - "ordinal": 2, - "name": "title", - "type_info": "Varchar" - }, - { - "ordinal": 3, - "name": "description", - "type_info": "Varchar" - }, - { - "ordinal": 4, - "name": "downloads", - "type_info": "Int4" - }, - { - "ordinal": 5, - "name": "follows", - "type_info": "Int4" - }, - { - "ordinal": 6, - "name": "icon_url", - "type_info": "Varchar" - }, - { - "ordinal": 7, - "name": "body", - "type_info": "Varchar" - }, - { - "ordinal": 8, - "name": "body_url", - "type_info": "Varchar" - }, - { - "ordinal": 9, - "name": "published", - "type_info": "Timestamptz" - }, - { - "ordinal": 10, - "name": "updated", - "type_info": "Timestamptz" - }, - { - "ordinal": 11, - "name": "status", - "type_info": "Int4" - }, - { - "ordinal": 12, - "name": "issues_url", - "type_info": "Varchar" - }, - { - "ordinal": 13, - "name": "source_url", - "type_info": "Varchar" - }, - { - "ordinal": 14, - "name": "wiki_url", - "type_info": "Varchar" - }, - { - "ordinal": 15, - "name": "discord_url", - "type_info": "Varchar" - }, - { - "ordinal": 16, - "name": "license_url", - "type_info": "Varchar" - }, - { - "ordinal": 17, - "name": "team_id", - "type_info": "Int8" - }, - { - "ordinal": 18, - "name": "client_side", - "type_info": "Int4" - }, - { - "ordinal": 19, - "name": "server_side", - "type_info": "Int4" - }, - { - "ordinal": 20, - "name": "license", - "type_info": "Int4" - }, - { - "ordinal": 21, - "name": "slug", - "type_info": "Varchar" - }, - { - "ordinal": 22, - "name": "moderation_message", - "type_info": "Varchar" - }, - { - "ordinal": 23, - "name": "moderation_message_body", - "type_info": "Varchar" - }, - { - "ordinal": 24, - "name": "status_name", - "type_info": "Varchar" - }, - { - "ordinal": 25, - "name": "client_side_type", - "type_info": "Varchar" - }, - { - "ordinal": 26, - "name": "server_side_type", - "type_info": "Varchar" - }, - { - "ordinal": 27, - "name": "short", - "type_info": "Varchar" - }, - { - "ordinal": 28, - "name": "license_name", - "type_info": "Varchar" - }, - { - "ordinal": 29, - "name": "project_type_name", - "type_info": "Varchar" - }, - { - "ordinal": 30, - "name": "categories", - "type_info": "Text" - }, - { - "ordinal": 31, - "name": "versions", - "type_info": "Text" - }, - { - "ordinal": 32, - "name": "gallery", - "type_info": "Text" - }, - { - "ordinal": 33, - "name": "donations", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Int8Array" - ] - }, - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - null, - null, - null, - null - ] - } - }, "ac2d17b7d7147b14f072c15ffa214c14f32f27ffa6a3c2b2a5f80f3ad49ca5e9": { "query": "\n SELECT id FROM users\n WHERE LOWER(username) = LOWER($1)\n ", "describe": { diff --git a/src/database/models/project_item.rs b/src/database/models/project_item.rs index f16dc4f5e..becc0404b 100644 --- a/src/database/models/project_item.rs +++ b/src/database/models/project_item.rs @@ -169,8 +169,8 @@ pub struct Project { pub description: String, pub body: String, pub body_url: Option, - pub published: time::OffsetDateTime, - pub updated: time::OffsetDateTime, + pub published: OffsetDateTime, + pub updated: OffsetDateTime, pub status: StatusId, pub downloads: i32, pub follows: i32, @@ -537,30 +537,29 @@ impl Project { } pub async fn get_from_slug_or_project_id<'a, 'b, E>( - slug_or_project_id: String, + slug_or_project_id: &str, executor: E, ) -> Result, sqlx::error::Error> where E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy, { - let id_option = crate::models::ids::base62_impl::parse_base62( - &*slug_or_project_id.clone(), - ) - .ok(); + let id_option = + crate::models::ids::base62_impl::parse_base62(slug_or_project_id) + .ok(); if let Some(id) = id_option { let mut project = Project::get(ProjectId(id as i64), executor).await?; if project.is_none() { - project = Project::get_from_slug(&slug_or_project_id, executor) + project = Project::get_from_slug(slug_or_project_id, executor) .await?; } Ok(project) } else { let project = - Project::get_from_slug(&slug_or_project_id, executor).await?; + Project::get_from_slug(slug_or_project_id, executor).await?; Ok(project) } @@ -612,8 +611,8 @@ impl Project { m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body, s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, pt.name project_type_name, STRING_AGG(DISTINCT c.category, ' ~~~~ ') categories, STRING_AGG(DISTINCT v.id::text, ' ~~~~ ') versions, - STRING_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' ') || ' |||| ' || mg.created, ' ~~~~ ') gallery, - STRING_AGG(DISTINCT md.joining_platform_id || ' |||| ' || md.url || ' |||| ' || dp.short || ' |||| ' || dp.name, ' ~~~~ ') donations + STRING_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || mg.created || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' '), ' ~~~~ ') gallery, + STRING_AGG(DISTINCT md.joining_platform_id || ' |||| ' || dp.short || ' |||| ' || dp.name || ' |||| ' || md.url, ' ~~~~ ') donations FROM mods m INNER JOIN project_types pt ON pt.id = m.project_type INNER JOIN statuses s ON s.id = m.status @@ -685,10 +684,12 @@ impl Project { if strings.len() >= 3 { Some(DonationUrl { project_id: id, - 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(), + platform_id: DonationPlatformId( + strings[0].parse().unwrap_or(0), + ), + platform_short: strings[1].to_string(), + platform_name: strings[2].to_string(), + url: strings[3].to_string(), }) } else { None @@ -708,17 +709,21 @@ impl Project { project_id: id, image_url: strings[0].to_string(), featured: strings[1].parse().unwrap_or(false), - title: if strings[2] == " " { - None - } else { - Some(strings[2].to_string()) - }, - description: if strings[3] == " " { + title: if strings[3] == " " { None } else { Some(strings[3].to_string()) }, - created: OffsetDateTime::parse(strings[4], time::Format::Rfc3339).unwrap_or_else(|_| OffsetDateTime::now_utc()) + description: if strings[4] == " " { + None + } else { + Some(strings[4].to_string()) + }, + created: OffsetDateTime::parse( + strings[2], + time::Format::Rfc3339, + ) + .unwrap_or_else(|_| OffsetDateTime::now_utc()), }) } else { None @@ -726,11 +731,17 @@ impl Project { }) .flatten() .collect(), - status: crate::models::projects::ProjectStatus::from_str(&m.status_name), + status: crate::models::projects::ProjectStatus::from_str( + &m.status_name, + ), license_id: m.short, license_name: m.license_name, - client_side: crate::models::projects::SideType::from_str(&m.client_side_type), - server_side: crate::models::projects::SideType::from_str(&m.server_side_type), + client_side: crate::models::projects::SideType::from_str( + &m.client_side_type, + ), + server_side: crate::models::projects::SideType::from_str( + &m.server_side_type, + ), })) } else { Ok(None) @@ -746,7 +757,8 @@ impl Project { { use futures::TryStreamExt; - let project_ids_parsed: Vec = project_ids.into_iter().map(|x| x.0).collect(); + let project_ids_parsed: Vec = + project_ids.into_iter().map(|x| x.0).collect(); sqlx::query!( " SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows, @@ -756,8 +768,8 @@ impl Project { m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body, s.status status_name, cs.name client_side_type, ss.name server_side_type, l.short short, l.name license_name, pt.name project_type_name, STRING_AGG(DISTINCT c.category, ' ~~~~ ') categories, STRING_AGG(DISTINCT v.id::text, ' ~~~~ ') versions, - STRING_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' ') || ' |||| ' || mg.created, ' ~~~~ ') gallery, - STRING_AGG(DISTINCT md.joining_platform_id || ' |||| ' || md.url || ' |||| ' || dp.short || ' |||| ' || dp.name, ' ~~~~ ') donations + STRING_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || mg.created || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' '), ' ~~~~ ') gallery, + STRING_AGG(DISTINCT md.joining_platform_id || ' |||| ' || dp.short || ' |||| ' || dp.name || ' |||| ' || md.url, ' ~~~~ ') donations FROM mods m INNER JOIN project_types pt ON pt.id = m.project_type INNER JOIN statuses s ON s.id = m.status @@ -821,9 +833,9 @@ impl Project { project_id: ProjectId(id), image_url: strings[0].to_string(), featured: strings[1].parse().unwrap_or(false), - title: if strings[2] == " " { None } else { Some(strings[2].to_string()) }, - description: if strings[3] == " " { None } else { Some(strings[3].to_string()) }, - created: OffsetDateTime::parse(strings[4], time::Format::Rfc3339).unwrap_or_else(|_| OffsetDateTime::now_utc()) + title: if strings[3] == " " { None } else { Some(strings[3].to_string()) }, + description: if strings[4] == " " { None } else { Some(strings[4].to_string()) }, + created: OffsetDateTime::parse(strings[2], time::Format::Rfc3339).unwrap_or_else(|_| OffsetDateTime::now_utc()) }) } else { None @@ -842,9 +854,9 @@ impl Project { Some(DonationUrl { project_id: ProjectId(id), 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(), + platform_short: strings[1].to_string(), + platform_name: strings[2].to_string(), + url: strings[3].to_string(), }) } else { None diff --git a/src/database/models/version_item.rs b/src/database/models/version_item.rs index 2ce9725b7..3ddd20b9b 100644 --- a/src/database/models/version_item.rs +++ b/src/database/models/version_item.rs @@ -616,9 +616,9 @@ impl Version { v.changelog changelog, v.changelog_url changelog_url, v.date_published date_published, v.downloads downloads, v.version_type version_type, v.featured featured, STRING_AGG(DISTINCT gv.version, ' ~~~~ ') game_versions, STRING_AGG(DISTINCT l.loader, ' ~~~~ ') loaders, - STRING_AGG(DISTINCT f.id || ' |||| ' || f.filename || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url, ' ~~~~ ') files, + STRING_AGG(DISTINCT f.id || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url || ' |||| ' || f.filename, ' ~~~~ ') files, STRING_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id, ' ~~~~ ') hashes, - STRING_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || COALESCE(d.dependency_file_name, ' ') || ' |||| ' || d.dependency_type, ' ~~~~ ') dependencies + STRING_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || d.dependency_type || ' |||| ' || COALESCE(d.dependency_file_name, ' '), ' ~~~~ ') dependencies FROM versions v LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id @@ -679,17 +679,18 @@ impl Version { for hash in &hashes { if (hash.0).0 == file_id.0 { - file_hashes.insert(hash.1.clone(), hash.2.clone()); + file_hashes + .insert(hash.1.clone(), hash.2.clone()); } } Some(QueryFile { id: file_id, - url: file[4].to_string(), - filename: file[1].to_string(), + url: file[3].to_string(), + filename: file[4].to_string(), hashes: file_hashes, - primary: file[2].parse().unwrap_or(false), - size: file[3].parse().unwrap_or(0) + primary: file[1].parse().unwrap_or(false), + size: file[2].parse().unwrap_or(0), }) } else { None @@ -733,8 +734,12 @@ impl Version { Err(_) => None, }, }, - file_name: if dependency[2] == " " { None } else { Some(dependency[2].to_string())}, - dependency_type: dependency[3].to_string(), + file_name: if dependency[3] == " " { + None + } else { + Some(dependency[3].to_string()) + }, + dependency_type: dependency[2].to_string(), }) } else { None @@ -758,16 +763,17 @@ impl Version { { use futures::stream::TryStreamExt; - let version_ids_parsed: Vec = version_ids.into_iter().map(|x| x.0).collect(); + 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, v.version_type version_type, v.featured featured, STRING_AGG(DISTINCT gv.version, ' ~~~~ ') game_versions, STRING_AGG(DISTINCT l.loader, ' ~~~~ ') loaders, - STRING_AGG(DISTINCT f.id || ' |||| ' || f.filename || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url, ' ~~~~ ') files, + STRING_AGG(DISTINCT f.id || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url || ' |||| ' || f.filename, ' ~~~~ ') files, STRING_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id, ' ~~~~ ') hashes, - STRING_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || COALESCE(d.dependency_file_name, ' ') || ' |||| ' || d.dependency_type, ' ~~~~ ') dependencies + STRING_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || d.dependency_type || ' |||| ' || COALESCE(d.dependency_file_name, ' '), ' ~~~~ ') dependencies FROM versions v LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id @@ -824,11 +830,11 @@ impl Version { Some(QueryFile { id: file_id, - url: file[4].to_string(), - filename: file[1].to_string(), + url: file[3].to_string(), + filename: file[4].to_string(), hashes: file_hashes, - primary: file[2].parse().unwrap_or(false), - size: file[3].parse().unwrap_or(0) + primary: file[1].parse().unwrap_or(false), + size: file[2].parse().unwrap_or(0), }) } else { None @@ -859,8 +865,12 @@ impl Version { Err(_) => None, }, }, - file_name: if dependency[2] == " " { None } else { Some(dependency[2].to_string())}, - dependency_type: dependency[3].to_string(), + file_name: if dependency[3] == " " { + None + } else { + Some(dependency[3].to_string()) + }, + dependency_type: dependency[2].to_string(), }) } else { None diff --git a/src/main.rs b/src/main.rs index e3c40b367..de0314cf1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use crate::file_hosting::S3Host; +use crate::queue::download::DownloadQueue; use crate::ratelimit::errors::ARError; use crate::ratelimit::memory::{MemoryStore, MemoryStoreActor}; use crate::ratelimit::middleware::RateLimiter; @@ -16,6 +17,7 @@ mod database; mod file_hosting; mod health; mod models; +mod queue; mod ratelimit; mod routes; mod scheduler; @@ -183,11 +185,27 @@ async fn main() -> std::io::Result<()> { scheduler::schedule_versions(&mut scheduler, pool.clone(), skip_initial); + let download_queue = Arc::new(DownloadQueue::new()); + + let pool_ref = pool.clone(); + let download_queue_ref = download_queue.clone(); + scheduler.run(std::time::Duration::from_secs(30), move || { + let pool_ref = pool_ref.clone(); + let download_queue_ref = download_queue_ref.clone(); + + async move { + info!("Indexing download queue"); + let result = download_queue_ref.index(&pool_ref).await; + if let Err(e) = result { + warn!("Indexing download queue failed: {:?}", e); + } + info!("Done indexing download queue"); + } + }); + let ip_salt = Pepper { - pepper: crate::models::ids::Base62Id( - crate::models::ids::random_base62(11), - ) - .to_string(), + pepper: models::ids::Base62Id(models::ids::random_base62(11)) + .to_string(), }; let store = MemoryStore::new(); @@ -243,6 +261,7 @@ async fn main() -> std::io::Result<()> { .app_data(web::Data::new(pool.clone())) .app_data(web::Data::new(file_host.clone())) .app_data(web::Data::new(search_config.clone())) + .app_data(web::Data::new(download_queue.clone())) .app_data(web::Data::new(ip_salt.clone())) .configure(routes::v1_config) .configure(routes::v2_config) diff --git a/src/queue/download.rs b/src/queue/download.rs new file mode 100644 index 000000000..f608adeda --- /dev/null +++ b/src/queue/download.rs @@ -0,0 +1,58 @@ +use crate::database::models::{DatabaseError, ProjectId, VersionId}; +use sqlx::PgPool; +use tokio::sync::Mutex; + +pub struct DownloadQueue { + queue: Mutex>, +} + +// Batches download transactions every thirty seconds +impl DownloadQueue { + pub fn new() -> Self { + DownloadQueue { + queue: Mutex::new(Vec::with_capacity(1000)), + } + } + pub async fn add(&self, project_id: ProjectId, version_id: VersionId) { + self.queue.lock().await.push((project_id, version_id)); + } + + pub async fn take(&self) -> Vec<(ProjectId, VersionId)> { + let mut queue = self.queue.lock().await; + let len = queue.len(); + + std::mem::replace(&mut queue, Vec::with_capacity(len)) + } + + pub async fn index(&self, pool: &PgPool) -> Result<(), DatabaseError> { + let queue = self.take().await; + + if queue.len() > 0 { + let mut transaction = pool.begin().await?; + + for (project_id, version_id) in queue { + sqlx::query!( + "UPDATE versions + SET downloads = downloads + 1 + WHERE (id = $1)", + version_id as VersionId + ) + .execute(&mut *transaction) + .await?; + + sqlx::query!( + "UPDATE mods + SET downloads = downloads + 1 + WHERE (id = $1)", + project_id as ProjectId + ) + .execute(&mut *transaction) + .await?; + } + + transaction.commit().await?; + } + + Ok(()) + } +} diff --git a/src/queue/mod.rs b/src/queue/mod.rs new file mode 100644 index 000000000..674b799ed --- /dev/null +++ b/src/queue/mod.rs @@ -0,0 +1 @@ +pub mod download; diff --git a/src/routes/admin.rs b/src/routes/admin.rs index 79c5c043b..e6f32178f 100644 --- a/src/routes/admin.rs +++ b/src/routes/admin.rs @@ -1,9 +1,11 @@ use crate::models::ids::ProjectId; use crate::routes::ApiError; use crate::util::guards::admin_key_guard; +use crate::DownloadQueue; use actix_web::{patch, web, HttpResponse}; use serde::Deserialize; use sqlx::PgPool; +use std::sync::Arc; #[derive(Deserialize)] pub struct DownloadBody { @@ -17,6 +19,7 @@ pub struct DownloadBody { pub async fn count_download( pool: web::Data, download_body: web::Json, + download_queue: web::Data>, ) -> Result { let project_id: crate::database::models::ids::ProjectId = download_body.hash.into(); @@ -49,27 +52,12 @@ pub async fn count_download( )); }; - let mut transaction = pool.begin().await?; - - sqlx::query!( - "UPDATE versions - SET downloads = downloads + 1 - WHERE (id = $1)", - version_id - ) - .execute(&mut *transaction) - .await?; - - sqlx::query!( - "UPDATE mods - SET downloads = downloads + 1 - WHERE (id = $1)", - project_id - ) - .execute(&mut *transaction) - .await?; - - transaction.commit().await?; + download_queue + .add( + crate::database::models::ProjectId(project_id), + crate::database::models::VersionId(version_id), + ) + .await; Ok(HttpResponse::Ok().body("")) } diff --git a/src/routes/projects.rs b/src/routes/projects.rs index 9c80f8b4f..0171e4e67 100644 --- a/src/routes/projects.rs +++ b/src/routes/projects.rs @@ -38,11 +38,10 @@ pub async fn projects_get( web::Query(ids): web::Query, pool: web::Data, ) -> Result { - let project_ids = - serde_json::from_str::>(&*ids.ids)? - .into_iter() - .map(|x| x.into()) - .collect(); + let project_ids = serde_json::from_str::>(&*ids.ids)? + .into_iter() + .map(|x| x.into()) + .collect(); let projects_data = database::models::Project::get_many_full(project_ids, &**pool).await?; @@ -871,8 +870,7 @@ pub async fn project_icon_edit( let project_item = database::models::Project::get_from_slug_or_project_id( - string.clone(), - &**pool, + &string, &**pool, ) .await? .ok_or_else(|| { @@ -963,8 +961,7 @@ pub async fn delete_project_icon( let string = info.into_inner().0; let project_item = database::models::Project::get_from_slug_or_project_id( - string.clone(), - &**pool, + &string, &**pool, ) .await? .ok_or_else(|| { @@ -1053,8 +1050,7 @@ pub async fn add_gallery_item( let project_item = database::models::Project::get_from_slug_or_project_id( - string.clone(), - &**pool, + &string, &**pool, ) .await? .ok_or_else(|| { @@ -1173,8 +1169,7 @@ pub async fn edit_gallery_item( })?; let project_item = database::models::Project::get_from_slug_or_project_id( - string.clone(), - &**pool, + &string, &**pool, ) .await? .ok_or_else(|| { @@ -1301,8 +1296,7 @@ pub async fn delete_gallery_item( let string = info.into_inner().0; let project_item = database::models::Project::get_from_slug_or_project_id( - string.clone(), - &**pool, + &string, &**pool, ) .await? .ok_or_else(|| { @@ -1385,8 +1379,7 @@ pub async fn project_delete( let string = info.into_inner().0; let project = database::models::Project::get_from_slug_or_project_id( - string.clone(), - &**pool, + &string, &**pool, ) .await? .ok_or_else(|| { @@ -1446,14 +1439,15 @@ pub async fn project_follow( let user = get_user_from_headers(req.headers(), &**pool).await?; let string = info.into_inner().0; - let result = - database::models::Project::get_from_slug_or_project_id(string, &**pool) - .await? - .ok_or_else(|| { - ApiError::InvalidInput( - "The specified project does not exist!".to_string(), - ) - })?; + let result = database::models::Project::get_from_slug_or_project_id( + &string, &**pool, + ) + .await? + .ok_or_else(|| { + ApiError::InvalidInput( + "The specified project does not exist!".to_string(), + ) + })?; let user_id: database::models::ids::UserId = user.id.into(); let project_id: database::models::ids::ProjectId = result.id; @@ -1514,14 +1508,15 @@ pub async fn project_unfollow( let user = get_user_from_headers(req.headers(), &**pool).await?; let string = info.into_inner().0; - let result = - database::models::Project::get_from_slug_or_project_id(string, &**pool) - .await? - .ok_or_else(|| { - ApiError::InvalidInput( - "The specified project does not exist!".to_string(), - ) - })?; + let result = database::models::Project::get_from_slug_or_project_id( + &string, &**pool, + ) + .await? + .ok_or_else(|| { + ApiError::InvalidInput( + "The specified project does not exist!".to_string(), + ) + })?; let user_id: database::models::ids::UserId = user.id.into(); let project_id = result.id; diff --git a/src/routes/teams.rs b/src/routes/teams.rs index 793e7997e..e98f05db6 100644 --- a/src/routes/teams.rs +++ b/src/routes/teams.rs @@ -20,7 +20,7 @@ pub async fn team_members_get_project( let string = info.into_inner().0; let project_data = crate::database::models::Project::get_from_slug_or_project_id( - string, &**pool, + &string, &**pool, ) .await?; diff --git a/src/routes/v1/versions.rs b/src/routes/v1/versions.rs index 26ba98983..9cb335c8f 100644 --- a/src/routes/v1/versions.rs +++ b/src/routes/v1/versions.rs @@ -63,9 +63,10 @@ pub async fn version_list( ) -> Result { let string = info.into_inner().0; - let result = - database::models::Project::get_from_slug_or_project_id(string, &**pool) - .await?; + let result = database::models::Project::get_from_slug_or_project_id( + &string, &**pool, + ) + .await?; if let Some(project) = result { let id = project.id; @@ -161,11 +162,10 @@ pub async fn versions_get( ids: web::Query, pool: web::Data, ) -> Result { - let version_ids = - serde_json::from_str::>(&*ids.ids)? - .into_iter() - .map(|x| x.into()) - .collect(); + let version_ids = serde_json::from_str::>(&*ids.ids)? + .into_iter() + .map(|x| x.into()) + .collect(); let versions_data = database::models::Version::get_many_full(version_ids, &**pool).await?; @@ -180,7 +180,7 @@ pub async fn versions_get( #[get("{version_id}")] pub async fn version_get( - info: web::Path<(models::ids::VersionId,)>, + info: web::Path<(VersionId,)>, pool: web::Data, ) -> Result { let id = info.into_inner().0; diff --git a/src/routes/version_creation.rs b/src/routes/version_creation.rs index 97f11f41f..d1ea00157 100644 --- a/src/routes/version_creation.rs +++ b/src/routes/version_creation.rs @@ -756,12 +756,14 @@ pub async fn upload_file( } for file in files { - dependencies.push(DependencyBuilder { - project_id: None, - version_id: None, - file_name: Some(file.to_string()), - dependency_type: DependencyType::Required.to_string(), - }); + if !file.is_empty() { + dependencies.push(DependencyBuilder { + project_id: None, + version_id: None, + file_name: Some(file.to_string()), + dependency_type: DependencyType::Required.to_string(), + }); + } } } } diff --git a/src/util/auth.rs b/src/util/auth.rs index 7061d378c..40b93ec2c 100644 --- a/src/util/auth.rs +++ b/src/util/auth.rs @@ -135,7 +135,7 @@ pub async fn is_authorized( if user.role.is_mod() { authorized = true; } else { - let user_id: database::models::ids::UserId = user.id.into(); + let user_id: models::ids::UserId = user.id.into(); let project_exists = sqlx::query!( "SELECT EXISTS(SELECT 1 FROM team_members WHERE team_id = $1 AND user_id = $2)",