From 8ea3b71d18115660b5c3bd84d75dc5a0530f3057 Mon Sep 17 00:00:00 2001 From: Leo Kettmeir Date: Tue, 3 Mar 2026 10:47:25 +0100 Subject: [PATCH] fix: improve package version queries performance (#1325) --- ...b5a4154c08d16fa6c4707df30cf2c3a495f0.json} | 10 +- ...64e413364b365d4e5ef42dc5d8eddbd2136d.json} | 18 +-- ...fefbd34b68f46fa47054f313911626db62d90.json | 96 +++++++++++++++ ...7ea60ff698ee85cf3299c533c2de6e16cd49.json} | 10 +- ...5041bbe3fa6dd79d3726b7907df3e98e9f4e.json} | 18 +-- ...0c376d4bd4efa1015fd682348faed5832966.json} | 10 +- ...7d6c8e47b68e1d3fff1a06ccc5532aca1eba.json} | 26 ++-- ...3ef651d4ae7b102ce180a17eb54da600651fc.json | 95 +++++++++++++++ api/src/api/package.rs | 11 +- api/src/api/types.rs | 28 +++-- api/src/db/database.rs | 115 +++++++++--------- api/src/db/models.rs | 18 ++- .../package/(_components)/PackageHeader.tsx | 7 +- frontend/utils/api_types.ts | 2 +- 14 files changed, 314 insertions(+), 150 deletions(-) rename api/.sqlx/{query-fee18c67559361eef0489ede3c6b14b65b105d2bc1116ab59530d103cf0848ba.json => query-310f27038755fa26c5d497554c80b5a4154c08d16fa6c4707df30cf2c3a495f0.json} (79%) rename api/.sqlx/{query-fb8d500eab239e634e5d6d7a4e704359cb3633bfeb207d92f90ed642c5c16e17.json => query-35a29be7b322f3535c48ecbc509f64e413364b365d4e5ef42dc5d8eddbd2136d.json} (68%) create mode 100644 api/.sqlx/query-6b5d8952594514f5b296c98585ffefbd34b68f46fa47054f313911626db62d90.json rename api/.sqlx/{query-534d4975e1cefb978e644c1401f083361a8ecf58b2f185f28c2684091538796a.json => query-72366428bf790d5b8af2f78098137ea60ff698ee85cf3299c533c2de6e16cd49.json} (77%) rename api/.sqlx/{query-b2960e0ffa33c3712ebefe71ce377af2fab0debc622abe5cc2a0a041c9d62754.json => query-8aabfceedb18bd0ce7182f9d10035041bbe3fa6dd79d3726b7907df3e98e9f4e.json} (64%) rename api/.sqlx/{query-46f22b0a1095e370760d3f58454a43b7d34ab53ad7bc638460faa748dfaa9b8f.json => query-a0dbd5a38a3313453c3222b34efe0c376d4bd4efa1015fd682348faed5832966.json} (84%) rename api/.sqlx/{query-fd2edb5ead047d016e41eebe4c86cf4b202e8f29f2c02c8914fec2fcb04df1af.json => query-a2ced49ae1b7905db50fe78bcf157d6c8e47b68e1d3fff1a06ccc5532aca1eba.json} (70%) create mode 100644 api/.sqlx/query-dc7cb05a2f6a83c6013f2d86baa3ef651d4ae7b102ce180a17eb54da600651fc.json diff --git a/api/.sqlx/query-fee18c67559361eef0489ede3c6b14b65b105d2bc1116ab59530d103cf0848ba.json b/api/.sqlx/query-310f27038755fa26c5d497554c80b5a4154c08d16fa6c4707df30cf2c3a495f0.json similarity index 79% rename from api/.sqlx/query-fee18c67559361eef0489ede3c6b14b65b105d2bc1116ab59530d103cf0848ba.json rename to api/.sqlx/query-310f27038755fa26c5d497554c80b5a4154c08d16fa6c4707df30cf2c3a495f0.json index 917f3d826..5c4f64dc5 100644 --- a/api/.sqlx/query-fee18c67559361eef0489ede3c6b14b65b105d2bc1116ab59530d103cf0848ba.json +++ b/api/.sqlx/query-310f27038755fa26c5d497554c80b5a4154c08d16fa6c4707df30cf2c3a495f0.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license,\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"newer_versions_count!\",\n (SELECT COALESCE(SUM(dl.count), 0)\n FROM version_download_counts_24h as dl\n WHERE dl.scope = package_versions.scope\n AND dl.package = package_versions.name\n AND dl.version = package_versions.version) as \"lifetime_download_count!\"\n FROM package_versions\n WHERE scope = $1 AND name = $2 AND version = $3", + "query": "SELECT scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license,\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"newer_versions_count!\"\n FROM package_versions\n WHERE scope = $1 AND name = $2 AND version = $3", "describe": { "columns": [ { @@ -72,11 +72,6 @@ "ordinal": 13, "name": "newer_versions_count!", "type_info": "Int8" - }, - { - "ordinal": 14, - "name": "lifetime_download_count!", - "type_info": "Int8" } ], "parameters": { @@ -100,9 +95,8 @@ false, true, true, - null, null ] }, - "hash": "fee18c67559361eef0489ede3c6b14b65b105d2bc1116ab59530d103cf0848ba" + "hash": "310f27038755fa26c5d497554c80b5a4154c08d16fa6c4707df30cf2c3a495f0" } diff --git a/api/.sqlx/query-fb8d500eab239e634e5d6d7a4e704359cb3633bfeb207d92f90ed642c5c16e17.json b/api/.sqlx/query-35a29be7b322f3535c48ecbc509f64e413364b365d4e5ef42dc5d8eddbd2136d.json similarity index 68% rename from api/.sqlx/query-fb8d500eab239e634e5d6d7a4e704359cb3633bfeb207d92f90ed642c5c16e17.json rename to api/.sqlx/query-35a29be7b322f3535c48ecbc509f64e413364b365d4e5ef42dc5d8eddbd2136d.json index 3d2d74240..6371d0706 100644 --- a/api/.sqlx/query-fb8d500eab239e634e5d6d7a4e704359cb3633bfeb207d92f90ed642c5c16e17.json +++ b/api/.sqlx/query-35a29be7b322f3535c48ecbc509f64e413364b365d4e5ef42dc5d8eddbd2136d.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE package_versions\n SET is_yanked = $4\n WHERE scope = $1 AND name = $2 AND version = $3\n RETURNING scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license,\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"newer_versions_count!\",\n (SELECT COALESCE(SUM(dl.count), 0)\n FROM version_download_counts_24h as dl\n WHERE dl.scope = package_versions.scope\n AND dl.package = package_versions.name\n AND dl.version = package_versions.version) as \"lifetime_download_count!\"", + "query": "UPDATE package_versions\n SET is_yanked = $4\n WHERE scope = $1 AND name = $2 AND version = $3\n RETURNING scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license", "describe": { "columns": [ { @@ -67,16 +67,6 @@ "ordinal": 12, "name": "license", "type_info": "Text" - }, - { - "ordinal": 13, - "name": "newer_versions_count!", - "type_info": "Int8" - }, - { - "ordinal": 14, - "name": "lifetime_download_count!", - "type_info": "Int8" } ], "parameters": { @@ -100,10 +90,8 @@ false, false, true, - true, - null, - null + true ] }, - "hash": "fb8d500eab239e634e5d6d7a4e704359cb3633bfeb207d92f90ed642c5c16e17" + "hash": "35a29be7b322f3535c48ecbc509f64e413364b365d4e5ef42dc5d8eddbd2136d" } diff --git a/api/.sqlx/query-6b5d8952594514f5b296c98585ffefbd34b68f46fa47054f313911626db62d90.json b/api/.sqlx/query-6b5d8952594514f5b296c98585ffefbd34b68f46fa47054f313911626db62d90.json new file mode 100644 index 000000000..99eb94c09 --- /dev/null +++ b/api/.sqlx/query-6b5d8952594514f5b296c98585ffefbd34b68f46fa47054f313911626db62d90.json @@ -0,0 +1,96 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license\n FROM package_versions\n WHERE scope = $1 AND name = $2 AND version = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "scope: ScopeName", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "name: PackageName", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "version: Version", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 4, + "name": "readme_path: PackagePath", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "exports: ExportsMap", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "is_yanked", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "uses_npm", + "type_info": "Bool" + }, + { + "ordinal": 8, + "name": "meta: PackageVersionMeta", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "updated_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 10, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 11, + "name": "rekor_log_id", + "type_info": "Text" + }, + { + "ordinal": 12, + "name": "license", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + true, + true + ] + }, + "hash": "6b5d8952594514f5b296c98585ffefbd34b68f46fa47054f313911626db62d90" +} diff --git a/api/.sqlx/query-534d4975e1cefb978e644c1401f083361a8ecf58b2f185f28c2684091538796a.json b/api/.sqlx/query-72366428bf790d5b8af2f78098137ea60ff698ee85cf3299c533c2de6e16cd49.json similarity index 77% rename from api/.sqlx/query-534d4975e1cefb978e644c1401f083361a8ecf58b2f185f28c2684091538796a.json rename to api/.sqlx/query-72366428bf790d5b8af2f78098137ea60ff698ee85cf3299c533c2de6e16cd49.json index fba9ef909..3f42d642a 100644 --- a/api/.sqlx/query-534d4975e1cefb978e644c1401f083361a8ecf58b2f185f28c2684091538796a.json +++ b/api/.sqlx/query-72366428bf790d5b8af2f78098137ea60ff698ee85cf3299c533c2de6e16cd49.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license,\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"newer_versions_count!\",\n (SELECT COALESCE(SUM(dl.count), 0)\n FROM version_download_counts_24h as dl\n WHERE dl.scope = package_versions.scope\n AND dl.package = package_versions.name\n AND dl.version = package_versions.version) as \"lifetime_download_count!\"\n FROM package_versions\n WHERE scope = $1 AND name = $2 AND version NOT LIKE '%-%' AND is_yanked = false\n ORDER BY version DESC\n LIMIT 1", + "query": "SELECT scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license,\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"newer_versions_count!\"\n FROM package_versions\n WHERE scope = $1 AND name = $2 AND version NOT LIKE '%-%' AND is_yanked = false\n ORDER BY version DESC\n LIMIT 1", "describe": { "columns": [ { @@ -72,11 +72,6 @@ "ordinal": 13, "name": "newer_versions_count!", "type_info": "Int8" - }, - { - "ordinal": 14, - "name": "lifetime_download_count!", - "type_info": "Int8" } ], "parameters": { @@ -99,9 +94,8 @@ false, true, true, - null, null ] }, - "hash": "534d4975e1cefb978e644c1401f083361a8ecf58b2f185f28c2684091538796a" + "hash": "72366428bf790d5b8af2f78098137ea60ff698ee85cf3299c533c2de6e16cd49" } diff --git a/api/.sqlx/query-b2960e0ffa33c3712ebefe71ce377af2fab0debc622abe5cc2a0a041c9d62754.json b/api/.sqlx/query-8aabfceedb18bd0ce7182f9d10035041bbe3fa6dd79d3726b7907df3e98e9f4e.json similarity index 64% rename from api/.sqlx/query-b2960e0ffa33c3712ebefe71ce377af2fab0debc622abe5cc2a0a041c9d62754.json rename to api/.sqlx/query-8aabfceedb18bd0ce7182f9d10035041bbe3fa6dd79d3726b7907df3e98e9f4e.json index 4159d1d36..877d6b399 100644 --- a/api/.sqlx/query-b2960e0ffa33c3712ebefe71ce377af2fab0debc622abe5cc2a0a041c9d62754.json +++ b/api/.sqlx/query-8aabfceedb18bd0ce7182f9d10035041bbe3fa6dd79d3726b7907df3e98e9f4e.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT package_versions.scope as \"scope: ScopeName\", package_versions.name as \"name: PackageName\", package_versions.version as \"version: Version\", package_versions.user_id, package_versions.readme_path as \"readme_path: PackagePath\", package_versions.exports as \"exports: ExportsMap\", package_versions.is_yanked, package_versions.uses_npm, package_versions.meta as \"meta: PackageVersionMeta\", package_versions.updated_at, package_versions.created_at, package_versions.rekor_log_id, package_versions.license,\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"newer_versions_count!\",\n (SELECT COALESCE(SUM(dl.count), 0)\n FROM version_download_counts_24h as dl\n WHERE dl.scope = package_versions.scope\n AND dl.package = package_versions.name\n AND dl.version = package_versions.version) as \"lifetime_download_count!\"\n FROM package_versions\n JOIN packages ON packages.scope = package_versions.scope AND packages.name = package_versions.name\n WHERE NOT packages.is_archived\n ORDER BY package_versions.created_at DESC\n LIMIT 10", + "query": "SELECT package_versions.scope as \"scope: ScopeName\", package_versions.name as \"name: PackageName\", package_versions.version as \"version: Version\", package_versions.user_id, package_versions.readme_path as \"readme_path: PackagePath\", package_versions.exports as \"exports: ExportsMap\", package_versions.is_yanked, package_versions.uses_npm, package_versions.meta as \"meta: PackageVersionMeta\", package_versions.updated_at, package_versions.created_at, package_versions.rekor_log_id, package_versions.license\n FROM package_versions\n JOIN packages ON packages.scope = package_versions.scope AND packages.name = package_versions.name\n WHERE NOT packages.is_archived\n ORDER BY package_versions.created_at DESC\n LIMIT 10", "describe": { "columns": [ { @@ -67,16 +67,6 @@ "ordinal": 12, "name": "license", "type_info": "Text" - }, - { - "ordinal": 13, - "name": "newer_versions_count!", - "type_info": "Int8" - }, - { - "ordinal": 14, - "name": "lifetime_download_count!", - "type_info": "Int8" } ], "parameters": { @@ -95,10 +85,8 @@ false, false, true, - true, - null, - null + true ] }, - "hash": "b2960e0ffa33c3712ebefe71ce377af2fab0debc622abe5cc2a0a041c9d62754" + "hash": "8aabfceedb18bd0ce7182f9d10035041bbe3fa6dd79d3726b7907df3e98e9f4e" } diff --git a/api/.sqlx/query-46f22b0a1095e370760d3f58454a43b7d34ab53ad7bc638460faa748dfaa9b8f.json b/api/.sqlx/query-a0dbd5a38a3313453c3222b34efe0c376d4bd4efa1015fd682348faed5832966.json similarity index 84% rename from api/.sqlx/query-46f22b0a1095e370760d3f58454a43b7d34ab53ad7bc638460faa748dfaa9b8f.json rename to api/.sqlx/query-a0dbd5a38a3313453c3222b34efe0c376d4bd4efa1015fd682348faed5832966.json index 5ea339b0a..a60794a6e 100644 --- a/api/.sqlx/query-46f22b0a1095e370760d3f58454a43b7d34ab53ad7bc638460faa748dfaa9b8f.json +++ b/api/.sqlx/query-a0dbd5a38a3313453c3222b34efe0c376d4bd4efa1015fd682348faed5832966.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO package_versions (scope, name, version, user_id, readme_path, exports, uses_npm, meta)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8)\n RETURNING scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license,\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"newer_versions_count!\",\n (SELECT COALESCE(SUM(dl.count), 0)\n FROM version_download_counts_24h as dl\n WHERE dl.scope = package_versions.scope\n AND dl.package = package_versions.name\n AND dl.version = package_versions.version) as \"lifetime_download_count!\"", + "query": "INSERT INTO package_versions (scope, name, version, user_id, readme_path, exports, uses_npm, meta)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8)\n RETURNING scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license,\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"newer_versions_count!\"", "describe": { "columns": [ { @@ -72,11 +72,6 @@ "ordinal": 13, "name": "newer_versions_count!", "type_info": "Int8" - }, - { - "ordinal": 14, - "name": "lifetime_download_count!", - "type_info": "Int8" } ], "parameters": { @@ -105,9 +100,8 @@ false, true, true, - null, null ] }, - "hash": "46f22b0a1095e370760d3f58454a43b7d34ab53ad7bc638460faa748dfaa9b8f" + "hash": "a0dbd5a38a3313453c3222b34efe0c376d4bd4efa1015fd682348faed5832966" } diff --git a/api/.sqlx/query-fd2edb5ead047d016e41eebe4c86cf4b202e8f29f2c02c8914fec2fcb04df1af.json b/api/.sqlx/query-a2ced49ae1b7905db50fe78bcf157d6c8e47b68e1d3fff1a06ccc5532aca1eba.json similarity index 70% rename from api/.sqlx/query-fd2edb5ead047d016e41eebe4c86cf4b202e8f29f2c02c8914fec2fcb04df1af.json rename to api/.sqlx/query-a2ced49ae1b7905db50fe78bcf157d6c8e47b68e1d3fff1a06ccc5532aca1eba.json index d67bcc14c..08ee6292d 100644 --- a/api/.sqlx/query-fd2edb5ead047d016e41eebe4c86cf4b202e8f29f2c02c8914fec2fcb04df1af.json +++ b/api/.sqlx/query-a2ced49ae1b7905db50fe78bcf157d6c8e47b68e1d3fff1a06ccc5532aca1eba.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT package_versions.scope as \"package_version_scope: ScopeName\", package_versions.name as \"package_version_name: PackageName\", package_versions.version as \"package_version_version: Version\", package_versions.user_id as \"package_version_user_id\", package_versions.readme_path as \"package_version_readme_path: PackagePath\", package_versions.exports as \"package_version_exports: ExportsMap\", package_versions.is_yanked as \"package_version_is_yanked\", package_versions.uses_npm as \"package_version_uses_npm\", package_versions.meta as \"package_version_meta: PackageVersionMeta\", package_versions.updated_at as \"package_version_updated_at\", package_versions.created_at as \"package_version_created_at\", package_versions.rekor_log_id as \"package_version_rekor_log_id\", package_versions.license as \"package_version_license\",\n (SELECT COUNT(*)\n FROM package_versions AS pv\n WHERE pv.scope = package_versions.scope\n AND pv.name = package_versions.name\n AND pv.version > package_versions.version\n AND pv.version NOT LIKE '%-%'\n AND pv.is_yanked = false) as \"package_version_newer_versions_count!\",\n (SELECT COALESCE(SUM(dl.count), 0)\n FROM version_download_counts_24h as dl\n WHERE dl.scope = package_versions.scope\n AND dl.package = package_versions.name\n AND dl.version = package_versions.version) as \"package_version_lifetime_download_count!\",\n users.id as \"user_id?\", users.name as \"user_name?\", users.avatar_url as \"user_avatar_url?\", users.github_id as \"user_github_id\", users.updated_at as \"user_updated_at?\", users.created_at as \"user_created_at?\"\n FROM package_versions\n LEFT JOIN users ON package_versions.user_id = users.id\n WHERE package_versions.scope = $1 AND package_versions.name = $2\n ORDER BY package_versions.version DESC", + "query": "SELECT package_versions.scope as \"package_version_scope: ScopeName\", package_versions.name as \"package_version_name: PackageName\", package_versions.version as \"package_version_version: Version\", package_versions.user_id as \"package_version_user_id\", package_versions.readme_path as \"package_version_readme_path: PackagePath\", package_versions.exports as \"package_version_exports: ExportsMap\", package_versions.is_yanked as \"package_version_is_yanked\", package_versions.uses_npm as \"package_version_uses_npm\", package_versions.meta as \"package_version_meta: PackageVersionMeta\", package_versions.updated_at as \"package_version_updated_at\", package_versions.created_at as \"package_version_created_at\", package_versions.rekor_log_id as \"package_version_rekor_log_id\", package_versions.license as \"package_version_license\",\n users.id as \"user_id?\", users.name as \"user_name?\", users.avatar_url as \"user_avatar_url?\", users.github_id as \"user_github_id\", users.updated_at as \"user_updated_at?\", users.created_at as \"user_created_at?\"\n FROM package_versions\n LEFT JOIN users ON package_versions.user_id = users.id\n WHERE package_versions.scope = $1 AND package_versions.name = $2\n ORDER BY package_versions.version DESC", "describe": { "columns": [ { @@ -70,41 +70,31 @@ }, { "ordinal": 13, - "name": "package_version_newer_versions_count!", - "type_info": "Int8" - }, - { - "ordinal": 14, - "name": "package_version_lifetime_download_count!", - "type_info": "Int8" - }, - { - "ordinal": 15, "name": "user_id?", "type_info": "Uuid" }, { - "ordinal": 16, + "ordinal": 14, "name": "user_name?", "type_info": "Text" }, { - "ordinal": 17, + "ordinal": 15, "name": "user_avatar_url?", "type_info": "Text" }, { - "ordinal": 18, + "ordinal": 16, "name": "user_github_id", "type_info": "Int8" }, { - "ordinal": 19, + "ordinal": 17, "name": "user_updated_at?", "type_info": "Timestamptz" }, { - "ordinal": 20, + "ordinal": 18, "name": "user_created_at?", "type_info": "Timestamptz" } @@ -129,8 +119,6 @@ false, true, true, - null, - null, false, false, false, @@ -139,5 +127,5 @@ false ] }, - "hash": "fd2edb5ead047d016e41eebe4c86cf4b202e8f29f2c02c8914fec2fcb04df1af" + "hash": "a2ced49ae1b7905db50fe78bcf157d6c8e47b68e1d3fff1a06ccc5532aca1eba" } diff --git a/api/.sqlx/query-dc7cb05a2f6a83c6013f2d86baa3ef651d4ae7b102ce180a17eb54da600651fc.json b/api/.sqlx/query-dc7cb05a2f6a83c6013f2d86baa3ef651d4ae7b102ce180a17eb54da600651fc.json new file mode 100644 index 000000000..48e6ac8f7 --- /dev/null +++ b/api/.sqlx/query-dc7cb05a2f6a83c6013f2d86baa3ef651d4ae7b102ce180a17eb54da600651fc.json @@ -0,0 +1,95 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT scope as \"scope: ScopeName\", name as \"name: PackageName\", version as \"version: Version\", user_id, readme_path as \"readme_path: PackagePath\", exports as \"exports: ExportsMap\", is_yanked, uses_npm, meta as \"meta: PackageVersionMeta\", updated_at, created_at, rekor_log_id, license\n FROM package_versions\n WHERE scope = $1 AND name = $2 AND version NOT LIKE '%-%' AND is_yanked = false\n ORDER BY version DESC\n LIMIT 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "scope: ScopeName", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "name: PackageName", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "version: Version", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 4, + "name": "readme_path: PackagePath", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "exports: ExportsMap", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "is_yanked", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "uses_npm", + "type_info": "Bool" + }, + { + "ordinal": 8, + "name": "meta: PackageVersionMeta", + "type_info": "Jsonb" + }, + { + "ordinal": 9, + "name": "updated_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 10, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 11, + "name": "rekor_log_id", + "type_info": "Text" + }, + { + "ordinal": 12, + "name": "license", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + true, + true + ] + }, + "hash": "dc7cb05a2f6a83c6013f2d86baa3ef651d4ae7b102ce180a17eb54da600651fc" +} diff --git a/api/src/api/package.rs b/api/src/api/package.rs index 296ad7bc4..072a2b92a 100644 --- a/api/src/api/package.rs +++ b/api/src/api/package.rs @@ -741,11 +741,16 @@ pub async fn get_version_handler( let maybe_version = match version { VersionOrLatest::Version(version) => { - db.get_package_version(&scope, &package, &version).await? + db.get_package_version_with_newer_versions_count( + &scope, &package, &version, + ) + .await? } VersionOrLatest::Latest => { - db.get_latest_unyanked_version_for_package(&scope, &package) - .await? + db.get_latest_unyanked_version_for_package_with_newer_versions_count( + &scope, &package, + ) + .await? } }; diff --git a/api/src/api/types.rs b/api/src/api/types.rs index 6549c8074..c9a132cac 100644 --- a/api/src/api/types.rs +++ b/api/src/api/types.rs @@ -617,8 +617,7 @@ pub struct ApiPackageVersion { pub version: Version, pub yanked: bool, pub uses_npm: bool, - pub newer_versions_count: u64, - pub lifetime_download_count: u64, + pub newer_versions_count: Option, pub rekor_log_id: Option, pub license: Option, pub readme_path: Option, @@ -673,8 +672,25 @@ impl From for ApiPackageVersion { version: value.version, yanked: value.is_yanked, uses_npm: value.uses_npm, - newer_versions_count: value.newer_versions_count as u64, - lifetime_download_count: value.lifetime_download_count as u64, + newer_versions_count: None, + rekor_log_id: value.rekor_log_id, + license: value.license, + readme_path: value.readme_path, + updated_at: value.updated_at, + created_at: value.created_at, + } + } +} + +impl From for ApiPackageVersion { + fn from(value: PackageVersionWithNewerVersionsCount) -> Self { + ApiPackageVersion { + scope: value.scope, + package: value.name, + version: value.version, + yanked: value.is_yanked, + uses_npm: value.uses_npm, + newer_versions_count: Some(value.newer_versions_count as u64), rekor_log_id: value.rekor_log_id, license: value.license, readme_path: value.readme_path, @@ -724,8 +740,6 @@ pub struct ApiPackageVersionWithUser { pub user: Option, pub yanked: bool, pub uses_npm: bool, - pub newer_versions_count: i64, - pub lifetime_download_count: i64, pub rekor_log_id: Option, pub readme_path: Option, pub updated_at: DateTime, @@ -747,8 +761,6 @@ impl From<(PackageVersion, Option)> for ApiPackageVersionWithUser { user: user.map(|user| user.into()), yanked: package_version.is_yanked, uses_npm: package_version.uses_npm, - newer_versions_count: package_version.newer_versions_count, - lifetime_download_count: package_version.lifetime_download_count, rekor_log_id: package_version.rekor_log_id, readme_path: package_version.readme_path, updated_at: package_version.updated_at, diff --git a/api/src/db/database.rs b/api/src/db/database.rs index 61523fdc3..3fedea1c5 100644 --- a/api/src/db/database.rs +++ b/api/src/db/database.rs @@ -1723,19 +1723,7 @@ impl Database { let updated = sqlx::query_as!( PackageVersion, - r#"SELECT package_versions.scope as "scope: ScopeName", package_versions.name as "name: PackageName", package_versions.version as "version: Version", package_versions.user_id, package_versions.readme_path as "readme_path: PackagePath", package_versions.exports as "exports: ExportsMap", package_versions.is_yanked, package_versions.uses_npm, package_versions.meta as "meta: PackageVersionMeta", package_versions.updated_at, package_versions.created_at, package_versions.rekor_log_id, package_versions.license, - (SELECT COUNT(*) - FROM package_versions AS pv - WHERE pv.scope = package_versions.scope - AND pv.name = package_versions.name - AND pv.version > package_versions.version - AND pv.version NOT LIKE '%-%' - AND pv.is_yanked = false) as "newer_versions_count!", - (SELECT COALESCE(SUM(dl.count), 0) - FROM version_download_counts_24h as dl - WHERE dl.scope = package_versions.scope - AND dl.package = package_versions.name - AND dl.version = package_versions.version) as "lifetime_download_count!" + r#"SELECT package_versions.scope as "scope: ScopeName", package_versions.name as "name: PackageName", package_versions.version as "version: Version", package_versions.user_id, package_versions.readme_path as "readme_path: PackagePath", package_versions.exports as "exports: ExportsMap", package_versions.is_yanked, package_versions.uses_npm, package_versions.meta as "meta: PackageVersionMeta", package_versions.updated_at, package_versions.created_at, package_versions.rekor_log_id, package_versions.license FROM package_versions JOIN packages ON packages.scope = package_versions.scope AND packages.name = package_versions.name WHERE NOT packages.is_archived @@ -1876,18 +1864,6 @@ impl Database { ) -> Result)>> { sqlx::query!( r#"SELECT package_versions.scope as "package_version_scope: ScopeName", package_versions.name as "package_version_name: PackageName", package_versions.version as "package_version_version: Version", package_versions.user_id as "package_version_user_id", package_versions.readme_path as "package_version_readme_path: PackagePath", package_versions.exports as "package_version_exports: ExportsMap", package_versions.is_yanked as "package_version_is_yanked", package_versions.uses_npm as "package_version_uses_npm", package_versions.meta as "package_version_meta: PackageVersionMeta", package_versions.updated_at as "package_version_updated_at", package_versions.created_at as "package_version_created_at", package_versions.rekor_log_id as "package_version_rekor_log_id", package_versions.license as "package_version_license", - (SELECT COUNT(*) - FROM package_versions AS pv - WHERE pv.scope = package_versions.scope - AND pv.name = package_versions.name - AND pv.version > package_versions.version - AND pv.version NOT LIKE '%-%' - AND pv.is_yanked = false) as "package_version_newer_versions_count!", - (SELECT COALESCE(SUM(dl.count), 0) - FROM version_download_counts_24h as dl - WHERE dl.scope = package_versions.scope - AND dl.package = package_versions.name - AND dl.version = package_versions.version) as "package_version_lifetime_download_count!", users.id as "user_id?", users.name as "user_name?", users.avatar_url as "user_avatar_url?", users.github_id as "user_github_id", users.updated_at as "user_updated_at?", users.created_at as "user_created_at?" FROM package_versions LEFT JOIN users ON package_versions.user_id = users.id @@ -1906,8 +1882,6 @@ impl Database { is_yanked: r.package_version_is_yanked, readme_path: r.package_version_readme_path, uses_npm: r.package_version_uses_npm, - newer_versions_count: r.package_version_newer_versions_count, - lifetime_download_count: r.package_version_lifetime_download_count, meta: r.package_version_meta, updated_at: r.package_version_updated_at, created_at: r.package_version_created_at, @@ -2004,6 +1978,30 @@ impl Database { ) -> Result> { sqlx::query_as!( PackageVersion, + r#"SELECT scope as "scope: ScopeName", name as "name: PackageName", version as "version: Version", user_id, readme_path as "readme_path: PackagePath", exports as "exports: ExportsMap", is_yanked, uses_npm, meta as "meta: PackageVersionMeta", updated_at, created_at, rekor_log_id, license + FROM package_versions + WHERE scope = $1 AND name = $2 AND version NOT LIKE '%-%' AND is_yanked = false + ORDER BY version DESC + LIMIT 1"#, + scope as _, + name as _, + ) + .fetch_optional(&self.pool) + .await + } + + #[instrument( + name = "Database::get_latest_unyanked_version_for_package_with_newer_versions_count", + skip(self), + err + )] + pub async fn get_latest_unyanked_version_for_package_with_newer_versions_count( + &self, + scope: &ScopeName, + name: &PackageName, + ) -> Result> { + sqlx::query_as!( + PackageVersionWithNewerVersionsCount, r#"SELECT scope as "scope: ScopeName", name as "name: PackageName", version as "version: Version", user_id, readme_path as "readme_path: PackagePath", exports as "exports: ExportsMap", is_yanked, uses_npm, meta as "meta: PackageVersionMeta", updated_at, created_at, rekor_log_id, license, (SELECT COUNT(*) FROM package_versions AS pv @@ -2011,12 +2009,7 @@ impl Database { AND pv.name = package_versions.name AND pv.version > package_versions.version AND pv.version NOT LIKE '%-%' - AND pv.is_yanked = false) as "newer_versions_count!", - (SELECT COALESCE(SUM(dl.count), 0) - FROM version_download_counts_24h as dl - WHERE dl.scope = package_versions.scope - AND dl.package = package_versions.name - AND dl.version = package_versions.version) as "lifetime_download_count!" + AND pv.is_yanked = false) as "newer_versions_count!" FROM package_versions WHERE scope = $1 AND name = $2 AND version NOT LIKE '%-%' AND is_yanked = false ORDER BY version DESC @@ -2065,6 +2058,30 @@ impl Database { ) -> Result> { sqlx::query_as!( PackageVersion, + r#"SELECT scope as "scope: ScopeName", name as "name: PackageName", version as "version: Version", user_id, readme_path as "readme_path: PackagePath", exports as "exports: ExportsMap", is_yanked, uses_npm, meta as "meta: PackageVersionMeta", updated_at, created_at, rekor_log_id, license + FROM package_versions + WHERE scope = $1 AND name = $2 AND version = $3"#, + scope as _, + name as _, + version as _ + ) + .fetch_optional(&self.pool) + .await + } + + #[instrument( + name = "Database::get_package_version_with_newer_versions_count", + skip(self), + err + )] + pub async fn get_package_version_with_newer_versions_count( + &self, + scope: &ScopeName, + name: &PackageName, + version: &Version, + ) -> Result> { + sqlx::query_as!( + PackageVersionWithNewerVersionsCount, r#"SELECT scope as "scope: ScopeName", name as "name: PackageName", version as "version: Version", user_id, readme_path as "readme_path: PackagePath", exports as "exports: ExportsMap", is_yanked, uses_npm, meta as "meta: PackageVersionMeta", updated_at, created_at, rekor_log_id, license, (SELECT COUNT(*) FROM package_versions AS pv @@ -2072,12 +2089,7 @@ impl Database { AND pv.name = package_versions.name AND pv.version > package_versions.version AND pv.version NOT LIKE '%-%' - AND pv.is_yanked = false) as "newer_versions_count!", - (SELECT COALESCE(SUM(dl.count), 0) - FROM version_download_counts_24h as dl - WHERE dl.scope = package_versions.scope - AND dl.package = package_versions.name - AND dl.version = package_versions.version) as "lifetime_download_count!" + AND pv.is_yanked = false) as "newer_versions_count!" FROM package_versions WHERE scope = $1 AND name = $2 AND version = $3"#, scope as _, @@ -2191,9 +2203,9 @@ impl Database { pub async fn create_package_version_for_test( &self, new_package_version: NewPackageVersion<'_>, - ) -> Result { + ) -> Result { sqlx::query_as!( - PackageVersion, + PackageVersionWithNewerVersionsCount, r#"INSERT INTO package_versions (scope, name, version, user_id, readme_path, exports, uses_npm, meta) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING scope as "scope: ScopeName", name as "name: PackageName", version as "version: Version", user_id, readme_path as "readme_path: PackagePath", exports as "exports: ExportsMap", is_yanked, uses_npm, meta as "meta: PackageVersionMeta", updated_at, created_at, rekor_log_id, license, @@ -2203,12 +2215,7 @@ impl Database { AND pv.name = package_versions.name AND pv.version > package_versions.version AND pv.version NOT LIKE '%-%' - AND pv.is_yanked = false) as "newer_versions_count!", - (SELECT COALESCE(SUM(dl.count), 0) - FROM version_download_counts_24h as dl - WHERE dl.scope = package_versions.scope - AND dl.package = package_versions.name - AND dl.version = package_versions.version) as "lifetime_download_count!""#, + AND pv.is_yanked = false) as "newer_versions_count!""#, new_package_version.scope as _, new_package_version.name as _, new_package_version.version as _, @@ -2253,19 +2260,7 @@ impl Database { r#"UPDATE package_versions SET is_yanked = $4 WHERE scope = $1 AND name = $2 AND version = $3 - RETURNING scope as "scope: ScopeName", name as "name: PackageName", version as "version: Version", user_id, readme_path as "readme_path: PackagePath", exports as "exports: ExportsMap", is_yanked, uses_npm, meta as "meta: PackageVersionMeta", updated_at, created_at, rekor_log_id, license, - (SELECT COUNT(*) - FROM package_versions AS pv - WHERE pv.scope = package_versions.scope - AND pv.name = package_versions.name - AND pv.version > package_versions.version - AND pv.version NOT LIKE '%-%' - AND pv.is_yanked = false) as "newer_versions_count!", - (SELECT COALESCE(SUM(dl.count), 0) - FROM version_download_counts_24h as dl - WHERE dl.scope = package_versions.scope - AND dl.package = package_versions.name - AND dl.version = package_versions.version) as "lifetime_download_count!""#, + RETURNING scope as "scope: ScopeName", name as "name: PackageName", version as "version: Version", user_id, readme_path as "readme_path: PackagePath", exports as "exports: ExportsMap", is_yanked, uses_npm, meta as "meta: PackageVersionMeta", updated_at, created_at, rekor_log_id, license"#, scope as _, name as _, version as _, diff --git a/api/src/db/models.rs b/api/src/db/models.rs index b4924774d..039c911bb 100644 --- a/api/src/db/models.rs +++ b/api/src/db/models.rs @@ -408,6 +408,23 @@ impl FromRow<'_, sqlx::postgres::PgRow> for Package { #[derive(Debug)] pub struct PackageVersion { + pub scope: ScopeName, + pub name: PackageName, + pub version: Version, + pub user_id: Option, + pub exports: ExportsMap, + pub is_yanked: bool, + pub readme_path: Option, + pub uses_npm: bool, + pub meta: PackageVersionMeta, + pub rekor_log_id: Option, + pub license: Option, + pub updated_at: DateTime, + pub created_at: DateTime, +} + +#[derive(Debug)] +pub struct PackageVersionWithNewerVersionsCount { pub scope: ScopeName, pub name: PackageName, pub version: Version, @@ -417,7 +434,6 @@ pub struct PackageVersion { pub readme_path: Option, pub uses_npm: bool, pub newer_versions_count: i64, - pub lifetime_download_count: i64, pub meta: PackageVersionMeta, pub rekor_log_id: Option, pub license: Option, diff --git a/frontend/routes/package/(_components)/PackageHeader.tsx b/frontend/routes/package/(_components)/PackageHeader.tsx index 0052f462d..986979dfd 100644 --- a/frontend/routes/package/(_components)/PackageHeader.tsx +++ b/frontend/routes/package/(_components)/PackageHeader.tsx @@ -77,10 +77,9 @@ export function PackageHeader({ : ( <> - is {selectedVersion.newerVersionsCount}{" "} - version{selectedVersion.newerVersionsCount !== 1 && "s"} - {" "} - behind {pkg.latestVersion} + is {selectedVersion.newerVersionsCount!}{" "} + version{selectedVersion.newerVersionsCount! !== 1 && + "s"} behind {pkg.latestVersion} {" "} — the latest version of @{pkg.scope}/{pkg.name}. diff --git a/frontend/utils/api_types.ts b/frontend/utils/api_types.ts index 95c63fd36..fcce0d44f 100644 --- a/frontend/utils/api_types.ts +++ b/frontend/utils/api_types.ts @@ -142,7 +142,7 @@ export interface PackageVersion { version: string; yanked: boolean; usesNpm: boolean; - newerVersionsCount: number; + newerVersionsCount: number | null; rekorLogId: string | null; license: string | null; readmePath: string;