From a7f23414a35f951c96a1059a858c99ce36bcfe45 Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Fri, 18 Oct 2024 14:36:08 +0200 Subject: [PATCH] Typed IDs for Release, Crate, Build --- ...f807bdbe47991abab7cd781f5dda5d8b8b56.json} | 6 +- ...aa404969aa8dc62389d0b405556d3c5bb25b.json} | 6 +- ...edaffcf58f68237f572e1c14801dc41fba3a.json} | 6 +- ...53f9d42da5178f23f1046c4df621a7d17307.json} | 6 +- ...fd6797b25b99a7112cb68a93a4fac5b07a23.json} | 7 +- ...75df1d6b84bb2c32adc999c6afa2cfce5314.json} | 6 +- ...c286fa0ec399ed98db0dda1ee81e6a6e7f3a.json} | 6 +- ...207c271cca9a18cebbade496d79eb1e5cae4.json} | 6 +- ...f07d801c711693e19ee40991f069b2393fec.json} | 6 +- ...f9b9afc273e362160421dda768d45c62f71b7.json | 23 +++ ...906e42a9dc37176ac1d357abd9ff1cfbb9c64.json | 22 +++ ...fd0374f2b8e650fa12c3931da3ee2e1ed82c.json} | 6 +- ...47d6071608366fd01f0d67db0991eb588b68.json} | 6 +- ...c92ae7ef49af5b09b0fc532f763947bd1aee.json} | 6 +- ...dee3ceecb713f8bd10869462726443a36ed5.json} | 10 +- ...09a1d493d797ee8c4c7d29457a81f86412c1.json} | 6 +- ...4d9b1b4acd434f966d1da2db30c509c6089d8.json | 22 --- ...b0fd730a139cb52ae92ac16cd662286dbe20.json} | 6 +- ...a2497eba27fcee660f3d92241eaeda02ac0f.json} | 6 +- ...22c402acbe2080f4d0c5079251532b7ceb87.json} | 6 +- Cargo.lock | 30 +++- Cargo.toml | 1 + src/bin/cratesfyi.rs | 9 +- src/build_queue.rs | 8 +- src/db/add_package.rs | 168 +++++++++++------- src/db/delete.rs | 59 +++--- src/db/mod.rs | 4 +- src/docbuilder/rustwide_builder.rs | 19 +- src/metrics/mod.rs | 15 +- src/storage/mod.rs | 44 ++--- src/test/fakes.rs | 16 +- src/web/build_details.rs | 12 +- src/web/builds.rs | 8 +- src/web/crate_details.rs | 46 ++--- src/web/mod.rs | 17 +- src/web/rustdoc.rs | 16 +- src/web/source.rs | 12 +- 37 files changed, 391 insertions(+), 267 deletions(-) rename .sqlx/{query-647d6a98ac5dfaa8d23bcab6687a343023ac052a6fda7ffc8124b70c67aa4b85.json => query-13002f36b4c77ce0055b591051f1f807bdbe47991abab7cd781f5dda5d8b8b56.json} (53%) rename .sqlx/{query-9d0cc50d980892931cad27d226b1a81864b4ee2f21315556356419c8356bb92b.json => query-1af366cf365f5b3899425ac6c4a7aa404969aa8dc62389d0b405556d3c5bb25b.json} (71%) rename .sqlx/{query-ac2450acd8bbec632668499a18c59644f6cfdc87bd6d280ca8db6a146929c8f5.json => query-2056327f710b8e427e21bf427a24edaffcf58f68237f572e1c14801dc41fba3a.json} (82%) rename .sqlx/{query-42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0.json => query-398d7622c18e45ddc5beffdcd5ec53f9d42da5178f23f1046c4df621a7d17307.json} (55%) rename .sqlx/{query-f586539bcbb4956768c424065ae7068198f91d2bbd7f176054ac58bcda3fcac6.json => query-4115addabb6f03cd0de31ac2ddeafd6797b25b99a7112cb68a93a4fac5b07a23.json} (56%) rename .sqlx/{query-0431f4fe27d903ad6af26ff36df056a9009e8746f8334ae32f0c900975968532.json => query-4329c81108a6b8832645e3a7256375df1d6b84bb2c32adc999c6afa2cfce5314.json} (95%) rename .sqlx/{query-f76e52369a85097581f2b2d74506c234eb0206d84805cbc8a38cddb0cd220d92.json => query-4b4bfd97b03f632357a68c84f281c286fa0ec399ed98db0dda1ee81e6a6e7f3a.json} (75%) rename .sqlx/{query-5999ff17eaffa304654fb25e0d6d530cfcb83011441716e7e44b7698b146c9c8.json => query-60dccddc0096cbf97fba82a98168207c271cca9a18cebbade496d79eb1e5cae4.json} (57%) rename .sqlx/{query-f42825d44f0c14d5ad0bcf76150c8689ac75e55acad3fc85c4cf998259abfc6f.json => query-7fda06d8c2a6cac88f9bf06b3480f07d801c711693e19ee40991f069b2393fec.json} (52%) create mode 100644 .sqlx/query-83dc17977f99a0b182f11efa80cf9b9afc273e362160421dda768d45c62f71b7.json create mode 100644 .sqlx/query-92415d8f64477bce37d6a1393c6906e42a9dc37176ac1d357abd9ff1cfbb9c64.json rename .sqlx/{query-162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c.json => query-9ae6841c8cdba0bdbb518d2ee0fdfd0374f2b8e650fa12c3931da3ee2e1ed82c.json} (65%) rename .sqlx/{query-d2fd21fb369b3105fe240d865fea786571008fe6088d142fd5f09a15b1a98344.json => query-a708e47c863614354e9a756da43b47d6071608366fd01f0d67db0991eb588b68.json} (81%) rename .sqlx/{query-20e23c3804282f206fcb8f2466a7d0d34e312cd5caeefcd77f0f1a94bd53fcb3.json => query-b7d805d65e97349dde8ac57e176bc92ae7ef49af5b09b0fc532f763947bd1aee.json} (61%) rename .sqlx/{query-1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87.json => query-c30ed3510f60d2ae638d941aa8e1dee3ceecb713f8bd10869462726443a36ed5.json} (59%) rename .sqlx/{query-75310f51de2b9064c400dfa4ea16bac989fb9ce51a2efe7661c000aa6ad932d4.json => query-c465bfd0ac82fe1e9ea7126e185d09a1d493d797ee8c4c7d29457a81f86412c1.json} (64%) delete mode 100644 .sqlx/query-cec7e0053fc9710683bb8b2c7f74d9b1b4acd434f966d1da2db30c509c6089d8.json rename .sqlx/{query-8d4e885b2e5a58241516f98b5739bbdca1225e112fb869858060666750b80f1f.json => query-d2c3a85119eea791d48d035c4593b0fd730a139cb52ae92ac16cd662286dbe20.json} (67%) rename .sqlx/{query-5ffff1acc8acd27b2f6b9ed3f5fb6b6222f7d0d45aa938a1d52791c11629e070.json => query-d675aff9079a87e41891c589eaffa2497eba27fcee660f3d92241eaeda02ac0f.json} (80%) rename .sqlx/{query-af9e79bde5aefc6653257d46a04f29442314330fd6707886889dd109fd7540fe.json => query-db4dacb4c559c87d8d6ed3b3b3e622c402acbe2080f4d0c5079251532b7ceb87.json} (57%) diff --git a/.sqlx/query-647d6a98ac5dfaa8d23bcab6687a343023ac052a6fda7ffc8124b70c67aa4b85.json b/.sqlx/query-13002f36b4c77ce0055b591051f1f807bdbe47991abab7cd781f5dda5d8b8b56.json similarity index 53% rename from .sqlx/query-647d6a98ac5dfaa8d23bcab6687a343023ac052a6fda7ffc8124b70c67aa4b85.json rename to .sqlx/query-13002f36b4c77ce0055b591051f1f807bdbe47991abab7cd781f5dda5d8b8b56.json index 8ab7c9d0a..667249a45 100644 --- a/.sqlx/query-647d6a98ac5dfaa8d23bcab6687a343023ac052a6fda7ffc8124b70c67aa4b85.json +++ b/.sqlx/query-13002f36b4c77ce0055b591051f1f807bdbe47991abab7cd781f5dda5d8b8b56.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, name\n FROM crates\n WHERE normalize_crate_name(name) = normalize_crate_name($1)", + "query": "\n SELECT\n id as \"id: CrateId\",\n name\n FROM crates\n WHERE normalize_crate_name(name) = normalize_crate_name($1)", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: CrateId", "type_info": "Int4" }, { @@ -24,5 +24,5 @@ false ] }, - "hash": "647d6a98ac5dfaa8d23bcab6687a343023ac052a6fda7ffc8124b70c67aa4b85" + "hash": "13002f36b4c77ce0055b591051f1f807bdbe47991abab7cd781f5dda5d8b8b56" } diff --git a/.sqlx/query-9d0cc50d980892931cad27d226b1a81864b4ee2f21315556356419c8356bb92b.json b/.sqlx/query-1af366cf365f5b3899425ac6c4a7aa404969aa8dc62389d0b405556d3c5bb25b.json similarity index 71% rename from .sqlx/query-9d0cc50d980892931cad27d226b1a81864b4ee2f21315556356419c8356bb92b.json rename to .sqlx/query-1af366cf365f5b3899425ac6c4a7aa404969aa8dc62389d0b405556d3c5bb25b.json index 3acb8522c..c6428a207 100644 --- a/.sqlx/query-9d0cc50d980892931cad27d226b1a81864b4ee2f21315556356419c8356bb92b.json +++ b/.sqlx/query-1af366cf365f5b3899425ac6c4a7aa404969aa8dc62389d0b405556d3c5bb25b.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "UPDATE releases\n SET yanked = $3\n FROM crates\n WHERE crates.id = releases.crate_id\n AND name = $1\n AND version = $2\n RETURNING crates.id\n ", + "query": "UPDATE releases\n SET yanked = $3\n FROM crates\n WHERE crates.id = releases.crate_id\n AND name = $1\n AND version = $2\n RETURNING crates.id as \"id: CrateId\"\n ", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: CrateId", "type_info": "Int4" } ], @@ -20,5 +20,5 @@ false ] }, - "hash": "9d0cc50d980892931cad27d226b1a81864b4ee2f21315556356419c8356bb92b" + "hash": "1af366cf365f5b3899425ac6c4a7aa404969aa8dc62389d0b405556d3c5bb25b" } diff --git a/.sqlx/query-ac2450acd8bbec632668499a18c59644f6cfdc87bd6d280ca8db6a146929c8f5.json b/.sqlx/query-2056327f710b8e427e21bf427a24edaffcf58f68237f572e1c14801dc41fba3a.json similarity index 82% rename from .sqlx/query-ac2450acd8bbec632668499a18c59644f6cfdc87bd6d280ca8db6a146929c8f5.json rename to .sqlx/query-2056327f710b8e427e21bf427a24edaffcf58f68237f572e1c14801dc41fba3a.json index 3d5210ed4..6d4f685e9 100644 --- a/.sqlx/query-ac2450acd8bbec632668499a18c59644f6cfdc87bd6d280ca8db6a146929c8f5.json +++ b/.sqlx/query-2056327f710b8e427e21bf427a24edaffcf58f68237f572e1c14801dc41fba3a.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "UPDATE builds\n SET\n rustc_version = $1,\n docsrs_version = $2,\n build_status = $3,\n build_server = $4,\n errors = $5,\n documentation_size = $6,\n rustc_nightly_date = $7,\n build_finished = NOW()\n WHERE\n id = $8\n RETURNING rid", + "query": "UPDATE builds\n SET\n rustc_version = $1,\n docsrs_version = $2,\n build_status = $3,\n build_server = $4,\n errors = $5,\n documentation_size = $6,\n rustc_nightly_date = $7,\n build_finished = NOW()\n WHERE\n id = $8\n RETURNING rid as \"rid: ReleaseId\" ", "describe": { "columns": [ { "ordinal": 0, - "name": "rid", + "name": "rid: ReleaseId", "type_info": "Int4" } ], @@ -36,5 +36,5 @@ false ] }, - "hash": "ac2450acd8bbec632668499a18c59644f6cfdc87bd6d280ca8db6a146929c8f5" + "hash": "2056327f710b8e427e21bf427a24edaffcf58f68237f572e1c14801dc41fba3a" } diff --git a/.sqlx/query-42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0.json b/.sqlx/query-398d7622c18e45ddc5beffdcd5ec53f9d42da5178f23f1046c4df621a7d17307.json similarity index 55% rename from .sqlx/query-42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0.json rename to .sqlx/query-398d7622c18e45ddc5beffdcd5ec53f9d42da5178f23f1046c4df621a7d17307.json index 552902659..48048871a 100644 --- a/.sqlx/query-42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0.json +++ b/.sqlx/query-398d7622c18e45ddc5beffdcd5ec53f9d42da5178f23f1046c4df621a7d17307.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT crate_id\n FROM releases\n WHERE id = $1", + "query": "SELECT crate_id as \"crate_id: CrateId\" FROM releases WHERE id = $1", "describe": { "columns": [ { "ordinal": 0, - "name": "crate_id", + "name": "crate_id: CrateId", "type_info": "Int4" } ], @@ -18,5 +18,5 @@ false ] }, - "hash": "42b5d5684d3813768048b4770997087ffc214cdaf08feb7bd25fa2b3ec7618b0" + "hash": "398d7622c18e45ddc5beffdcd5ec53f9d42da5178f23f1046c4df621a7d17307" } diff --git a/.sqlx/query-f586539bcbb4956768c424065ae7068198f91d2bbd7f176054ac58bcda3fcac6.json b/.sqlx/query-4115addabb6f03cd0de31ac2ddeafd6797b25b99a7112cb68a93a4fac5b07a23.json similarity index 56% rename from .sqlx/query-f586539bcbb4956768c424065ae7068198f91d2bbd7f176054ac58bcda3fcac6.json rename to .sqlx/query-4115addabb6f03cd0de31ac2ddeafd6797b25b99a7112cb68a93a4fac5b07a23.json index b25293ad7..aed78ccde 100644 --- a/.sqlx/query-f586539bcbb4956768c424065ae7068198f91d2bbd7f176054ac58bcda3fcac6.json +++ b/.sqlx/query-4115addabb6f03cd0de31ac2ddeafd6797b25b99a7112cb68a93a4fac5b07a23.json @@ -1,17 +1,16 @@ { "db_name": "PostgreSQL", - "query": "SELECT id FROM releases WHERE crate_id = $1 and version = $2", + "query": "SELECT id as \"id: CrateId\" FROM crates WHERE crates.name = $1", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: CrateId", "type_info": "Int4" } ], "parameters": { "Left": [ - "Int4", "Text" ] }, @@ -19,5 +18,5 @@ false ] }, - "hash": "f586539bcbb4956768c424065ae7068198f91d2bbd7f176054ac58bcda3fcac6" + "hash": "4115addabb6f03cd0de31ac2ddeafd6797b25b99a7112cb68a93a4fac5b07a23" } diff --git a/.sqlx/query-0431f4fe27d903ad6af26ff36df056a9009e8746f8334ae32f0c900975968532.json b/.sqlx/query-4329c81108a6b8832645e3a7256375df1d6b84bb2c32adc999c6afa2cfce5314.json similarity index 95% rename from .sqlx/query-0431f4fe27d903ad6af26ff36df056a9009e8746f8334ae32f0c900975968532.json rename to .sqlx/query-4329c81108a6b8832645e3a7256375df1d6b84bb2c32adc999c6afa2cfce5314.json index 6d79ada9d..608b3847c 100644 --- a/.sqlx/query-0431f4fe27d903ad6af26ff36df056a9009e8746f8334ae32f0c900975968532.json +++ b/.sqlx/query-4329c81108a6b8832645e3a7256375df1d6b84bb2c32adc999c6afa2cfce5314.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO releases (\n crate_id, version, release_time,\n dependencies, target_name, yanked,\n rustdoc_status, test_status, license, repository_url,\n homepage_url, description, description_long, readme,\n keywords, have_examples, downloads, files,\n doc_targets, is_library,\n documentation_url, default_target, features,\n repository_id, archive_storage, source_size\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9,\n $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $21, $22, $23, $24, $25, $26\n )\n ON CONFLICT (crate_id, version) DO UPDATE\n SET release_time = $3,\n dependencies = $4,\n target_name = $5,\n yanked = $6,\n rustdoc_status = $7,\n test_status = $8,\n license = $9,\n repository_url = $10,\n homepage_url = $11,\n description = $12,\n description_long = $13,\n readme = $14,\n keywords = $15,\n have_examples = $16,\n downloads = $17,\n files = $18,\n doc_targets = $19,\n is_library = $20,\n documentation_url = $21,\n default_target = $22,\n features = $23,\n repository_id = $24,\n archive_storage = $25,\n source_size = $26\n RETURNING id", + "query": "INSERT INTO releases (\n crate_id, version, release_time,\n dependencies, target_name, yanked,\n rustdoc_status, test_status, license, repository_url,\n homepage_url, description, description_long, readme,\n keywords, have_examples, downloads, files,\n doc_targets, is_library,\n documentation_url, default_target, features,\n repository_id, archive_storage, source_size\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9,\n $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $21, $22, $23, $24, $25, $26\n )\n ON CONFLICT (crate_id, version) DO UPDATE\n SET release_time = $3,\n dependencies = $4,\n target_name = $5,\n yanked = $6,\n rustdoc_status = $7,\n test_status = $8,\n license = $9,\n repository_url = $10,\n homepage_url = $11,\n description = $12,\n description_long = $13,\n readme = $14,\n keywords = $15,\n have_examples = $16,\n downloads = $17,\n files = $18,\n doc_targets = $19,\n is_library = $20,\n documentation_url = $21,\n default_target = $22,\n features = $23,\n repository_id = $24,\n archive_storage = $25,\n source_size = $26\n RETURNING id as \"id: ReleaseId\" ", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: ReleaseId", "type_info": "Int4" } ], @@ -66,5 +66,5 @@ false ] }, - "hash": "0431f4fe27d903ad6af26ff36df056a9009e8746f8334ae32f0c900975968532" + "hash": "4329c81108a6b8832645e3a7256375df1d6b84bb2c32adc999c6afa2cfce5314" } diff --git a/.sqlx/query-f76e52369a85097581f2b2d74506c234eb0206d84805cbc8a38cddb0cd220d92.json b/.sqlx/query-4b4bfd97b03f632357a68c84f281c286fa0ec399ed98db0dda1ee81e6a6e7f3a.json similarity index 75% rename from .sqlx/query-f76e52369a85097581f2b2d74506c234eb0206d84805cbc8a38cddb0cd220d92.json rename to .sqlx/query-4b4bfd97b03f632357a68c84f281c286fa0ec399ed98db0dda1ee81e6a6e7f3a.json index d37fec916..dd15d3dde 100644 --- a/.sqlx/query-f76e52369a85097581f2b2d74506c234eb0206d84805cbc8a38cddb0cd220d92.json +++ b/.sqlx/query-4b4bfd97b03f632357a68c84f281c286fa0ec399ed98db0dda1ee81e6a6e7f3a.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO releases (crate_id, version, archive_storage)\n VALUES ($1, $2, TRUE)\n ON CONFLICT (crate_id, version) DO UPDATE\n SET -- this `SET` is needed so the id is always returned.\n version = EXCLUDED.version\n RETURNING id", + "query": "INSERT INTO releases (crate_id, version, archive_storage)\n VALUES ($1, $2, TRUE)\n ON CONFLICT (crate_id, version) DO UPDATE\n SET -- this `SET` is needed so the id is always returned.\n version = EXCLUDED.version\n RETURNING id as \"id: ReleaseId\" ", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: ReleaseId", "type_info": "Int4" } ], @@ -19,5 +19,5 @@ false ] }, - "hash": "f76e52369a85097581f2b2d74506c234eb0206d84805cbc8a38cddb0cd220d92" + "hash": "4b4bfd97b03f632357a68c84f281c286fa0ec399ed98db0dda1ee81e6a6e7f3a" } diff --git a/.sqlx/query-5999ff17eaffa304654fb25e0d6d530cfcb83011441716e7e44b7698b146c9c8.json b/.sqlx/query-60dccddc0096cbf97fba82a98168207c271cca9a18cebbade496d79eb1e5cae4.json similarity index 57% rename from .sqlx/query-5999ff17eaffa304654fb25e0d6d530cfcb83011441716e7e44b7698b146c9c8.json rename to .sqlx/query-60dccddc0096cbf97fba82a98168207c271cca9a18cebbade496d79eb1e5cae4.json index 5124a3f5d..207adf0d5 100644 --- a/.sqlx/query-5999ff17eaffa304654fb25e0d6d530cfcb83011441716e7e44b7698b146c9c8.json +++ b/.sqlx/query-60dccddc0096cbf97fba82a98168207c271cca9a18cebbade496d79eb1e5cae4.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT crate_id FROM releases WHERE id = $1", + "query": "SELECT id as \"id: BuildId\" FROM builds WHERE rid = $1", "describe": { "columns": [ { "ordinal": 0, - "name": "crate_id", + "name": "id: BuildId", "type_info": "Int4" } ], @@ -18,5 +18,5 @@ false ] }, - "hash": "5999ff17eaffa304654fb25e0d6d530cfcb83011441716e7e44b7698b146c9c8" + "hash": "60dccddc0096cbf97fba82a98168207c271cca9a18cebbade496d79eb1e5cae4" } diff --git a/.sqlx/query-f42825d44f0c14d5ad0bcf76150c8689ac75e55acad3fc85c4cf998259abfc6f.json b/.sqlx/query-7fda06d8c2a6cac88f9bf06b3480f07d801c711693e19ee40991f069b2393fec.json similarity index 52% rename from .sqlx/query-f42825d44f0c14d5ad0bcf76150c8689ac75e55acad3fc85c4cf998259abfc6f.json rename to .sqlx/query-7fda06d8c2a6cac88f9bf06b3480f07d801c711693e19ee40991f069b2393fec.json index 845d73dae..60bddfbca 100644 --- a/.sqlx/query-f42825d44f0c14d5ad0bcf76150c8689ac75e55acad3fc85c4cf998259abfc6f.json +++ b/.sqlx/query-7fda06d8c2a6cac88f9bf06b3480f07d801c711693e19ee40991f069b2393fec.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT id FROM builds WHERE rid = $1", + "query": "\n SELECT crate_id as \"crate_id: CrateId\"\n FROM releases\n WHERE id = $1", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "crate_id: CrateId", "type_info": "Int4" } ], @@ -18,5 +18,5 @@ false ] }, - "hash": "f42825d44f0c14d5ad0bcf76150c8689ac75e55acad3fc85c4cf998259abfc6f" + "hash": "7fda06d8c2a6cac88f9bf06b3480f07d801c711693e19ee40991f069b2393fec" } diff --git a/.sqlx/query-83dc17977f99a0b182f11efa80cf9b9afc273e362160421dda768d45c62f71b7.json b/.sqlx/query-83dc17977f99a0b182f11efa80cf9b9afc273e362160421dda768d45c62f71b7.json new file mode 100644 index 000000000..7ca47cfe4 --- /dev/null +++ b/.sqlx/query-83dc17977f99a0b182f11efa80cf9b9afc273e362160421dda768d45c62f71b7.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT id as \"id: ReleaseId\" FROM releases WHERE crate_id = $1 and version = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id: ReleaseId", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "83dc17977f99a0b182f11efa80cf9b9afc273e362160421dda768d45c62f71b7" +} diff --git a/.sqlx/query-92415d8f64477bce37d6a1393c6906e42a9dc37176ac1d357abd9ff1cfbb9c64.json b/.sqlx/query-92415d8f64477bce37d6a1393c6906e42a9dc37176ac1d357abd9ff1cfbb9c64.json new file mode 100644 index 000000000..5745997b7 --- /dev/null +++ b/.sqlx/query-92415d8f64477bce37d6a1393c6906e42a9dc37176ac1d357abd9ff1cfbb9c64.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT id as \"id: CrateId\"\n FROM crates\n WHERE normalize_crate_name(name) = normalize_crate_name($1)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id: CrateId", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Varchar" + ] + }, + "nullable": [ + false + ] + }, + "hash": "92415d8f64477bce37d6a1393c6906e42a9dc37176ac1d357abd9ff1cfbb9c64" +} diff --git a/.sqlx/query-162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c.json b/.sqlx/query-9ae6841c8cdba0bdbb518d2ee0fdfd0374f2b8e650fa12c3931da3ee2e1ed82c.json similarity index 65% rename from .sqlx/query-162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c.json rename to .sqlx/query-9ae6841c8cdba0bdbb518d2ee0fdfd0374f2b8e650fa12c3931da3ee2e1ed82c.json index a41680000..4c7b5b71e 100644 --- a/.sqlx/query-162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c.json +++ b/.sqlx/query-9ae6841c8cdba0bdbb518d2ee0fdfd0374f2b8e650fa12c3931da3ee2e1ed82c.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n releases.id,\n releases.version,\n release_build_status.build_status as \"build_status!: BuildStatus\",\n releases.yanked,\n releases.is_library,\n releases.rustdoc_status,\n releases.target_name\n FROM releases\n INNER JOIN release_build_status ON releases.id = release_build_status.rid\n WHERE\n releases.crate_id = $1", + "query": "SELECT\n releases.id as \"id: ReleaseId\",\n releases.version,\n release_build_status.build_status as \"build_status!: BuildStatus\",\n releases.yanked,\n releases.is_library,\n releases.rustdoc_status,\n releases.target_name\n FROM releases\n INNER JOIN release_build_status ON releases.id = release_build_status.rid\n WHERE\n releases.crate_id = $1", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: ReleaseId", "type_info": "Int4" }, { @@ -65,5 +65,5 @@ true ] }, - "hash": "162c05df1f44bb48d087b6e6e4b3a8ab868b6d0cc20143b176522c0791a7023c" + "hash": "9ae6841c8cdba0bdbb518d2ee0fdfd0374f2b8e650fa12c3931da3ee2e1ed82c" } diff --git a/.sqlx/query-d2fd21fb369b3105fe240d865fea786571008fe6088d142fd5f09a15b1a98344.json b/.sqlx/query-a708e47c863614354e9a756da43b47d6071608366fd01f0d67db0991eb588b68.json similarity index 81% rename from .sqlx/query-d2fd21fb369b3105fe240d865fea786571008fe6088d142fd5f09a15b1a98344.json rename to .sqlx/query-a708e47c863614354e9a756da43b47d6071608366fd01f0d67db0991eb588b68.json index efef78f5e..9439ea53a 100644 --- a/.sqlx/query-d2fd21fb369b3105fe240d865fea786571008fe6088d142fd5f09a15b1a98344.json +++ b/.sqlx/query-a708e47c863614354e9a756da43b47d6071608366fd01f0d67db0991eb588b68.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO builds(rid, build_status, build_server, build_started)\n VALUES ($1, $2, $3, NOW())\n RETURNING id", + "query": "INSERT INTO builds(rid, build_status, build_server, build_started)\n VALUES ($1, $2, $3, NOW())\n RETURNING id as \"id: BuildId\" ", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: BuildId", "type_info": "Int4" } ], @@ -31,5 +31,5 @@ false ] }, - "hash": "d2fd21fb369b3105fe240d865fea786571008fe6088d142fd5f09a15b1a98344" + "hash": "a708e47c863614354e9a756da43b47d6071608366fd01f0d67db0991eb588b68" } diff --git a/.sqlx/query-20e23c3804282f206fcb8f2466a7d0d34e312cd5caeefcd77f0f1a94bd53fcb3.json b/.sqlx/query-b7d805d65e97349dde8ac57e176bc92ae7ef49af5b09b0fc532f763947bd1aee.json similarity index 61% rename from .sqlx/query-20e23c3804282f206fcb8f2466a7d0d34e312cd5caeefcd77f0f1a94bd53fcb3.json rename to .sqlx/query-b7d805d65e97349dde8ac57e176bc92ae7ef49af5b09b0fc532f763947bd1aee.json index 4678102cd..26969a794 100644 --- a/.sqlx/query-20e23c3804282f206fcb8f2466a7d0d34e312cd5caeefcd77f0f1a94bd53fcb3.json +++ b/.sqlx/query-b7d805d65e97349dde8ac57e176bc92ae7ef49af5b09b0fc532f763947bd1aee.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n builds.id,\n builds.rustc_version,\n builds.docsrs_version,\n builds.build_status as \"build_status: BuildStatus\",\n COALESCE(builds.build_finished, builds.build_started) as build_time,\n builds.errors\n FROM builds\n INNER JOIN releases ON releases.id = builds.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n WHERE\n crates.name = $1 AND\n releases.version = $2\n ORDER BY id DESC", + "query": "SELECT\n builds.id as \"id: BuildId\",\n builds.rustc_version,\n builds.docsrs_version,\n builds.build_status as \"build_status: BuildStatus\",\n COALESCE(builds.build_finished, builds.build_started) as build_time,\n builds.errors\n FROM builds\n INNER JOIN releases ON releases.id = builds.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n WHERE\n crates.name = $1 AND\n releases.version = $2\n ORDER BY builds.id DESC", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: BuildId", "type_info": "Int4" }, { @@ -60,5 +60,5 @@ true ] }, - "hash": "20e23c3804282f206fcb8f2466a7d0d34e312cd5caeefcd77f0f1a94bd53fcb3" + "hash": "b7d805d65e97349dde8ac57e176bc92ae7ef49af5b09b0fc532f763947bd1aee" } diff --git a/.sqlx/query-1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87.json b/.sqlx/query-c30ed3510f60d2ae638d941aa8e1dee3ceecb713f8bd10869462726443a36ed5.json similarity index 59% rename from .sqlx/query-1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87.json rename to .sqlx/query-c30ed3510f60d2ae638d941aa8e1dee3ceecb713f8bd10869462726443a36ed5.json index 384e3bbed..041427168 100644 --- a/.sqlx/query-1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87.json +++ b/.sqlx/query-c30ed3510f60d2ae638d941aa8e1dee3ceecb713f8bd10869462726443a36ed5.json @@ -1,16 +1,16 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n crates.id AS crate_id,\n releases.id AS release_id,\n crates.name,\n releases.version,\n releases.description,\n releases.dependencies,\n releases.readme,\n releases.description_long,\n releases.release_time,\n release_build_status.build_status as \"build_status!: BuildStatus\",\n -- this is the latest build ID that generated content\n -- it's used to invalidate some blob storage related caches.\n builds.id as \"latest_build_id?\",\n releases.rustdoc_status,\n releases.archive_storage,\n releases.repository_url,\n releases.homepage_url,\n releases.keywords,\n releases.have_examples,\n releases.target_name,\n repositories.host as \"repo_host?\",\n repositories.stars as \"repo_stars?\",\n repositories.forks as \"repo_forks?\",\n repositories.issues as \"repo_issues?\",\n repositories.name as \"repo_name?\",\n releases.is_library,\n releases.yanked,\n releases.doc_targets,\n releases.license,\n releases.documentation_url,\n releases.default_target,\n releases.source_size as \"source_size?\",\n builds.documentation_size as \"documentation_size?\",\n -- we're using the rustc version here to set the correct CSS file\n -- in the metadata.\n -- So we're only interested in successful builds here.\n builds.rustc_version as \"rustc_version?\",\n doc_coverage.total_items,\n doc_coverage.documented_items,\n doc_coverage.total_items_needing_examples,\n doc_coverage.items_with_examples\n FROM releases\n INNER JOIN release_build_status ON releases.id = release_build_status.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n LEFT JOIN doc_coverage ON doc_coverage.release_id = releases.id\n LEFT JOIN repositories ON releases.repository_id = repositories.id\n LEFT JOIN LATERAL (\n SELECT rustc_version, documentation_size, id\n FROM builds\n WHERE\n builds.rid = releases.id AND\n builds.build_status = 'success'\n ORDER BY builds.build_finished\n DESC LIMIT 1\n ) AS builds ON true\n WHERE crates.name = $1 AND releases.version = $2;", + "query": "SELECT\n crates.id AS \"crate_id: CrateId\",\n releases.id AS \"release_id: ReleaseId\",\n crates.name,\n releases.version,\n releases.description,\n releases.dependencies,\n releases.readme,\n releases.description_long,\n releases.release_time,\n release_build_status.build_status as \"build_status!: BuildStatus\",\n -- this is the latest build ID that generated content\n -- it's used to invalidate some blob storage related caches.\n builds.id as \"latest_build_id?: BuildId\",\n releases.rustdoc_status,\n releases.archive_storage,\n releases.repository_url,\n releases.homepage_url,\n releases.keywords,\n releases.have_examples,\n releases.target_name,\n repositories.host as \"repo_host?\",\n repositories.stars as \"repo_stars?\",\n repositories.forks as \"repo_forks?\",\n repositories.issues as \"repo_issues?\",\n repositories.name as \"repo_name?\",\n releases.is_library,\n releases.yanked,\n releases.doc_targets,\n releases.license,\n releases.documentation_url,\n releases.default_target,\n releases.source_size as \"source_size?\",\n builds.documentation_size as \"documentation_size?\",\n -- we're using the rustc version here to set the correct CSS file\n -- in the metadata.\n -- So we're only interested in successful builds here.\n builds.rustc_version as \"rustc_version?\",\n doc_coverage.total_items,\n doc_coverage.documented_items,\n doc_coverage.total_items_needing_examples,\n doc_coverage.items_with_examples\n FROM releases\n INNER JOIN release_build_status ON releases.id = release_build_status.rid\n INNER JOIN crates ON releases.crate_id = crates.id\n LEFT JOIN doc_coverage ON doc_coverage.release_id = releases.id\n LEFT JOIN repositories ON releases.repository_id = repositories.id\n LEFT JOIN LATERAL (\n SELECT rustc_version, documentation_size, id\n FROM builds\n WHERE\n builds.rid = releases.id AND\n builds.build_status = 'success'\n ORDER BY builds.build_finished\n DESC LIMIT 1\n ) AS builds ON true\n WHERE crates.name = $1 AND releases.version = $2;", "describe": { "columns": [ { "ordinal": 0, - "name": "crate_id", + "name": "crate_id: CrateId", "type_info": "Int4" }, { "ordinal": 1, - "name": "release_id", + "name": "release_id: ReleaseId", "type_info": "Int4" }, { @@ -66,7 +66,7 @@ }, { "ordinal": 10, - "name": "latest_build_id?", + "name": "latest_build_id?: BuildId", "type_info": "Int4" }, { @@ -240,5 +240,5 @@ true ] }, - "hash": "1f90e235d872d98342e4d0924f162bf1a053cf08270fa5648467453653d11d87" + "hash": "c30ed3510f60d2ae638d941aa8e1dee3ceecb713f8bd10869462726443a36ed5" } diff --git a/.sqlx/query-75310f51de2b9064c400dfa4ea16bac989fb9ce51a2efe7661c000aa6ad932d4.json b/.sqlx/query-c465bfd0ac82fe1e9ea7126e185d09a1d493d797ee8c4c7d29457a81f86412c1.json similarity index 64% rename from .sqlx/query-75310f51de2b9064c400dfa4ea16bac989fb9ce51a2efe7661c000aa6ad932d4.json rename to .sqlx/query-c465bfd0ac82fe1e9ea7126e185d09a1d493d797ee8c4c7d29457a81f86412c1.json index e72a473d3..b12ec5797 100644 --- a/.sqlx/query-75310f51de2b9064c400dfa4ea16bac989fb9ce51a2efe7661c000aa6ad932d4.json +++ b/.sqlx/query-c465bfd0ac82fe1e9ea7126e185d09a1d493d797ee8c4c7d29457a81f86412c1.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT id, name FROM crates ORDER BY name", + "query": "SELECT id as \"id: CrateId\", name FROM crates ORDER BY name", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: CrateId", "type_info": "Int4" }, { @@ -22,5 +22,5 @@ false ] }, - "hash": "75310f51de2b9064c400dfa4ea16bac989fb9ce51a2efe7661c000aa6ad932d4" + "hash": "c465bfd0ac82fe1e9ea7126e185d09a1d493d797ee8c4c7d29457a81f86412c1" } diff --git a/.sqlx/query-cec7e0053fc9710683bb8b2c7f74d9b1b4acd434f966d1da2db30c509c6089d8.json b/.sqlx/query-cec7e0053fc9710683bb8b2c7f74d9b1b4acd434f966d1da2db30c509c6089d8.json deleted file mode 100644 index 96cc1e631..000000000 --- a/.sqlx/query-cec7e0053fc9710683bb8b2c7f74d9b1b4acd434f966d1da2db30c509c6089d8.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT id FROM crates WHERE normalize_crate_name(name) = normalize_crate_name($1)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int4" - } - ], - "parameters": { - "Left": [ - "Varchar" - ] - }, - "nullable": [ - false - ] - }, - "hash": "cec7e0053fc9710683bb8b2c7f74d9b1b4acd434f966d1da2db30c509c6089d8" -} diff --git a/.sqlx/query-8d4e885b2e5a58241516f98b5739bbdca1225e112fb869858060666750b80f1f.json b/.sqlx/query-d2c3a85119eea791d48d035c4593b0fd730a139cb52ae92ac16cd662286dbe20.json similarity index 67% rename from .sqlx/query-8d4e885b2e5a58241516f98b5739bbdca1225e112fb869858060666750b80f1f.json rename to .sqlx/query-d2c3a85119eea791d48d035c4593b0fd730a139cb52ae92ac16cd662286dbe20.json index ed1802a4c..9df1cfcd5 100644 --- a/.sqlx/query-8d4e885b2e5a58241516f98b5739bbdca1225e112fb869858060666750b80f1f.json +++ b/.sqlx/query-d2c3a85119eea791d48d035c4593b0fd730a139cb52ae92ac16cd662286dbe20.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n releases.archive_storage,\n (\n SELECT id\n FROM builds\n WHERE\n builds.rid = releases.id AND\n builds.build_status = 'success'\n ORDER BY build_finished DESC\n LIMIT 1\n ) AS latest_build_id\n FROM releases\n INNER JOIN crates ON releases.crate_id = crates.id\n WHERE\n name = $1 AND\n version = $2", + "query": "SELECT\n releases.archive_storage,\n (\n SELECT id\n FROM builds\n WHERE\n builds.rid = releases.id AND\n builds.build_status = 'success'\n ORDER BY build_finished DESC\n LIMIT 1\n ) AS \"latest_build_id?: BuildId\"\n FROM releases\n INNER JOIN crates ON releases.crate_id = crates.id\n WHERE\n name = $1 AND\n version = $2", "describe": { "columns": [ { @@ -10,7 +10,7 @@ }, { "ordinal": 1, - "name": "latest_build_id", + "name": "latest_build_id?: BuildId", "type_info": "Int4" } ], @@ -25,5 +25,5 @@ null ] }, - "hash": "8d4e885b2e5a58241516f98b5739bbdca1225e112fb869858060666750b80f1f" + "hash": "d2c3a85119eea791d48d035c4593b0fd730a139cb52ae92ac16cd662286dbe20" } diff --git a/.sqlx/query-5ffff1acc8acd27b2f6b9ed3f5fb6b6222f7d0d45aa938a1d52791c11629e070.json b/.sqlx/query-d675aff9079a87e41891c589eaffa2497eba27fcee660f3d92241eaeda02ac0f.json similarity index 80% rename from .sqlx/query-5ffff1acc8acd27b2f6b9ed3f5fb6b6222f7d0d45aa938a1d52791c11629e070.json rename to .sqlx/query-d675aff9079a87e41891c589eaffa2497eba27fcee660f3d92241eaeda02ac0f.json index 19ceb7546..154247910 100644 --- a/.sqlx/query-5ffff1acc8acd27b2f6b9ed3f5fb6b6222f7d0d45aa938a1d52791c11629e070.json +++ b/.sqlx/query-d675aff9079a87e41891c589eaffa2497eba27fcee660f3d92241eaeda02ac0f.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "UPDATE builds\n SET\n build_status = $1,\n errors = $2\n WHERE id = $3\n RETURNING rid", + "query": "UPDATE builds\n SET\n build_status = $1,\n errors = $2\n WHERE id = $3\n RETURNING rid as \"rid: ReleaseId\" ", "describe": { "columns": [ { "ordinal": 0, - "name": "rid", + "name": "rid: ReleaseId", "type_info": "Int4" } ], @@ -31,5 +31,5 @@ false ] }, - "hash": "5ffff1acc8acd27b2f6b9ed3f5fb6b6222f7d0d45aa938a1d52791c11629e070" + "hash": "d675aff9079a87e41891c589eaffa2497eba27fcee660f3d92241eaeda02ac0f" } diff --git a/.sqlx/query-af9e79bde5aefc6653257d46a04f29442314330fd6707886889dd109fd7540fe.json b/.sqlx/query-db4dacb4c559c87d8d6ed3b3b3e622c402acbe2080f4d0c5079251532b7ceb87.json similarity index 57% rename from .sqlx/query-af9e79bde5aefc6653257d46a04f29442314330fd6707886889dd109fd7540fe.json rename to .sqlx/query-db4dacb4c559c87d8d6ed3b3b3e622c402acbe2080f4d0c5079251532b7ceb87.json index d064df252..67cdefa69 100644 --- a/.sqlx/query-af9e79bde5aefc6653257d46a04f29442314330fd6707886889dd109fd7540fe.json +++ b/.sqlx/query-db4dacb4c559c87d8d6ed3b3b3e622c402acbe2080f4d0c5079251532b7ceb87.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT id FROM crates WHERE name = $1", + "query": "SELECT id as \"id: CrateId\" FROM crates WHERE name = $1", "describe": { "columns": [ { "ordinal": 0, - "name": "id", + "name": "id: CrateId", "type_info": "Int4" } ], @@ -18,5 +18,5 @@ false ] }, - "hash": "af9e79bde5aefc6653257d46a04f29442314330fd6707886889dd109fd7540fe" + "hash": "db4dacb4c559c87d8d6ed3b3b3e622c402acbe2080f4d0c5079251532b7ceb87" } diff --git a/Cargo.lock b/Cargo.lock index 178b83aa7..0d9ff9e54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1594,6 +1594,27 @@ dependencies = [ "syn 2.0.86", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.86", + "unicode-xid", +] + [[package]] name = "deunicode" version = "1.6.0" @@ -1655,6 +1676,7 @@ dependencies = [ "crates-index-diff", "criterion", "dashmap", + "derive_more 1.0.0", "docsrs-metadata", "fn-error-context", "font-awesome-as-a-crate", @@ -5741,7 +5763,7 @@ checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" dependencies = [ "bitflags 1.3.2", "cssparser", - "derive_more", + "derive_more 0.99.18", "fxhash", "log", "matches", @@ -7044,6 +7066,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unicode_categories" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 88dd5e76c..f1cca5ee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ getrandom = "0.2.1" itertools = { version = "0.13.0" } rusqlite = { version = "0.32.1", features = ["bundled"] } hex = "0.4.3" +derive_more = { version = "1.0.0", features = ["display"] } # Async tokio = { version = "1.0", features = ["rt-multi-thread", "signal", "macros"] } diff --git a/src/bin/cratesfyi.rs b/src/bin/cratesfyi.rs index 2e2bd56f3..32871cdda 100644 --- a/src/bin/cratesfyi.rs +++ b/src/bin/cratesfyi.rs @@ -9,7 +9,7 @@ use anyhow::{anyhow, Context as _, Error, Result}; use axum::async_trait; use clap::{Parser, Subcommand, ValueEnum}; use docs_rs::cdn::CdnBackend; -use docs_rs::db::{self, add_path_into_database, Overrides, Pool}; +use docs_rs::db::{self, add_path_into_database, CrateId, Overrides, Pool}; use docs_rs::repositories::RepositoryStatsUpdater; use docs_rs::utils::{ get_config, get_crate_pattern_and_priority, list_crate_priorities, queue_builder, @@ -606,9 +606,10 @@ impl DatabaseSubcommand { let mut list_conn = pool.get_async().await?; let mut update_conn = pool.get_async().await?; - let mut result_stream = - sqlx::query!("SELECT id, name FROM crates ORDER BY name") - .fetch(&mut *list_conn); + let mut result_stream = sqlx::query!( + r#"SELECT id as "id: CrateId", name FROM crates ORDER BY name"# + ) + .fetch(&mut *list_conn); while let Some(row) = result_stream.next().await { let row = row?; diff --git a/src/build_queue.rs b/src/build_queue.rs index 3a843a4be..530e65a44 100644 --- a/src/build_queue.rs +++ b/src/build_queue.rs @@ -1,4 +1,4 @@ -use crate::db::{delete_crate, delete_version, update_latest_version_id, Pool}; +use crate::db::{delete_crate, delete_version, update_latest_version_id, CrateId, Pool}; use crate::docbuilder::PackageKind; use crate::error::Result; use crate::storage::AsyncStorage; @@ -368,14 +368,14 @@ impl AsyncBuildQueue { let activity = if yanked { "yanked" } else { "unyanked" }; if let Some(crate_id) = sqlx::query_scalar!( - "UPDATE releases + r#"UPDATE releases SET yanked = $3 FROM crates WHERE crates.id = releases.crate_id AND name = $1 AND version = $2 - RETURNING crates.id - ", + RETURNING crates.id as "id: CrateId" + "#, name, version, yanked, diff --git a/src/db/add_package.rs b/src/db/add_package.rs index ac6eed8b6..ff4c0101e 100644 --- a/src/db/add_package.rs +++ b/src/db/add_package.rs @@ -8,7 +8,9 @@ use crate::{ web::crate_details::{latest_release, releases_for_crate}, }; use anyhow::Context; +use derive_more::Display; use futures_util::stream::TryStreamExt; +use serde::Serialize; use serde_json::Value; use slug::slugify; use std::{ @@ -19,6 +21,18 @@ use std::{ }; use tracing::{debug, error, info, instrument}; +#[derive(Debug, Clone, Copy, Display, PartialEq, Eq, Hash, Serialize, sqlx::Type)] +#[sqlx(transparent)] +pub struct CrateId(pub i32); + +#[derive(Debug, Clone, Copy, Display, PartialEq, Eq, Hash, Serialize, sqlx::Type)] +#[sqlx(transparent)] +pub struct ReleaseId(pub i32); + +#[derive(Debug, Clone, Copy, Display, PartialEq, Eq, Hash, Serialize, sqlx::Type)] +#[sqlx(transparent)] +pub struct BuildId(pub i32); + /// Adds a package into database. /// /// Package must be built first. @@ -41,7 +55,7 @@ pub(crate) async fn add_package_into_database( repository_id: Option, archive_storage: bool, source_size: u64, -) -> Result { +) -> Result { debug!("Adding package into database"); let crate_id = initialize_crate(conn, &metadata_pkg.name).await?; let dependencies = convert_dependencies(metadata_pkg); @@ -50,8 +64,8 @@ pub(crate) async fn add_package_into_database( let features = get_features(metadata_pkg); let is_library = metadata_pkg.is_library(); - let release_id: i32 = sqlx::query_scalar!( - "INSERT INTO releases ( + let release_id = sqlx::query_scalar!( + r#"INSERT INTO releases ( crate_id, version, release_time, dependencies, target_name, yanked, rustdoc_status, test_status, license, repository_url, @@ -91,8 +105,8 @@ pub(crate) async fn add_package_into_database( repository_id = $24, archive_storage = $25, source_size = $26 - RETURNING id", - crate_id, + RETURNING id as "id: ReleaseId" "#, + crate_id.0, &metadata_pkg.version, registry_data.release_time, serde_json::to_value(dependencies)?, @@ -134,15 +148,18 @@ pub(crate) async fn add_package_into_database( Ok(release_id) } -pub async fn update_latest_version_id(conn: &mut sqlx::PgConnection, crate_id: i32) -> Result<()> { +pub async fn update_latest_version_id( + conn: &mut sqlx::PgConnection, + crate_id: CrateId, +) -> Result<()> { let releases = releases_for_crate(conn, crate_id).await?; sqlx::query!( "UPDATE crates SET latest_version_id = $2 WHERE id = $1", - crate_id, - latest_release(&releases).map(|release| release.id), + crate_id.0, + latest_release(&releases).map(|release| release.id.0), ) .execute(&mut *conn) .await?; @@ -150,7 +167,10 @@ pub async fn update_latest_version_id(conn: &mut sqlx::PgConnection, crate_id: i Ok(()) } -pub async fn update_build_status(conn: &mut sqlx::PgConnection, release_id: i32) -> Result<()> { +pub async fn update_build_status( + conn: &mut sqlx::PgConnection, + release_id: ReleaseId, +) -> Result<()> { sqlx::query!( "INSERT INTO release_build_status(rid, last_build_time, build_status) SELECT @@ -180,7 +200,7 @@ pub async fn update_build_status(conn: &mut sqlx::PgConnection, release_id: i32) SET last_build_time = EXCLUDED.last_build_time, build_status=EXCLUDED.build_status", - release_id, + release_id.0, ) .execute(&mut *conn) .await?; @@ -193,12 +213,16 @@ pub async fn update_build_status(conn: &mut sqlx::PgConnection, release_id: i32) Ok(()) } -async fn crate_id_from_release_id(conn: &mut sqlx::PgConnection, release_id: i32) -> Result { +async fn crate_id_from_release_id( + conn: &mut sqlx::PgConnection, + release_id: ReleaseId, +) -> Result { Ok(sqlx::query_scalar!( - "SELECT crate_id - FROM releases - WHERE id = $1", - release_id, + r#" + SELECT crate_id as "crate_id: CrateId" + FROM releases + WHERE id = $1"#, + release_id.0, ) .fetch_one(&mut *conn) .await?) @@ -207,7 +231,7 @@ async fn crate_id_from_release_id(conn: &mut sqlx::PgConnection, release_id: i32 #[instrument(skip(conn))] pub(crate) async fn add_doc_coverage( conn: &mut sqlx::PgConnection, - release_id: i32, + release_id: ReleaseId, doc_coverage: DocCoverage, ) -> Result { debug!("Adding doc coverage into database"); @@ -224,7 +248,7 @@ pub(crate) async fn add_doc_coverage( total_items_needing_examples = $4, items_with_examples = $5 RETURNING release_id", - &release_id, + release_id.0, &doc_coverage.total_items, &doc_coverage.documented_items, &doc_coverage.total_items_needing_examples, @@ -238,7 +262,7 @@ pub(crate) async fn add_doc_coverage( #[instrument(skip(conn))] pub(crate) async fn finish_build( conn: &mut sqlx::PgConnection, - build_id: i32, + build_id: BuildId, rustc_version: &str, docsrs_version: &str, build_status: BuildStatus, @@ -263,7 +287,7 @@ pub(crate) async fn finish_build( }; let release_id = sqlx::query_scalar!( - "UPDATE builds + r#"UPDATE builds SET rustc_version = $1, docsrs_version = $2, @@ -275,7 +299,7 @@ pub(crate) async fn finish_build( build_finished = NOW() WHERE id = $8 - RETURNING rid", + RETURNING rid as "rid: ReleaseId" "#, rustc_version, docsrs_version, build_status as BuildStatus, @@ -283,7 +307,7 @@ pub(crate) async fn finish_build( errors, documentation_size.map(|v| v as i64), rustc_date, - build_id, + build_id.0, ) .fetch_one(&mut *conn) .await?; @@ -296,20 +320,20 @@ pub(crate) async fn finish_build( #[instrument(skip(conn))] pub(crate) async fn update_build_with_error( conn: &mut sqlx::PgConnection, - build_id: i32, + build_id: BuildId, errors: Option<&str>, -) -> Result { +) -> Result { debug!("updating build with error"); let release_id = sqlx::query_scalar!( - "UPDATE builds + r#"UPDATE builds SET build_status = $1, errors = $2 WHERE id = $3 - RETURNING rid", + RETURNING rid as "rid: ReleaseId" "#, BuildStatus::Failure as BuildStatus, errors, - build_id, + build_id.0, ) .fetch_one(&mut *conn) .await?; @@ -319,7 +343,7 @@ pub(crate) async fn update_build_with_error( Ok(build_id) } -pub(crate) async fn initialize_crate(conn: &mut sqlx::PgConnection, name: &str) -> Result { +pub(crate) async fn initialize_crate(conn: &mut sqlx::PgConnection, name: &str) -> Result { sqlx::query_scalar!( "INSERT INTO crates (name) VALUES ($1) @@ -332,21 +356,22 @@ pub(crate) async fn initialize_crate(conn: &mut sqlx::PgConnection, name: &str) .fetch_one(&mut *conn) .await .map_err(Into::into) + .map(CrateId) } pub(crate) async fn initialize_release( conn: &mut sqlx::PgConnection, - crate_id: i32, + crate_id: CrateId, version: &str, -) -> Result { +) -> Result { let release_id = sqlx::query_scalar!( - "INSERT INTO releases (crate_id, version, archive_storage) + r#"INSERT INTO releases (crate_id, version, archive_storage) VALUES ($1, $2, TRUE) ON CONFLICT (crate_id, version) DO UPDATE SET -- this `SET` is needed so the id is always returned. version = EXCLUDED.version - RETURNING id", - crate_id, + RETURNING id as "id: ReleaseId" "#, + crate_id.0, version ) .fetch_one(&mut *conn) @@ -359,15 +384,15 @@ pub(crate) async fn initialize_release( pub(crate) async fn initialize_build( conn: &mut sqlx::PgConnection, - release_id: i32, -) -> Result { + release_id: ReleaseId, +) -> Result { let hostname = hostname::get()?; let build_id = sqlx::query_scalar!( - "INSERT INTO builds(rid, build_status, build_server, build_started) + r#"INSERT INTO builds(rid, build_status, build_server, build_started) VALUES ($1, $2, $3, NOW()) - RETURNING id", - release_id, + RETURNING id as "id: BuildId" "#, + release_id.0, BuildStatus::InProgress as BuildStatus, hostname.to_str().unwrap_or(""), ) @@ -479,7 +504,7 @@ fn read_rust_doc(file_path: &Path) -> Result> { async fn add_keywords_into_database( conn: &mut sqlx::PgConnection, pkg: &MetadataPackage, - release_id: i32, + release_id: ReleaseId, ) -> Result<()> { let wanted_keywords: HashMap = pkg .keywords @@ -518,7 +543,7 @@ async fn add_keywords_into_database( FROM keywords WHERE slug = ANY($2) ON CONFLICT DO NOTHING;", - release_id, + release_id.0, &wanted_keywords.keys().cloned().collect::>()[..], ) .execute(&mut *conn) @@ -534,9 +559,12 @@ pub async fn update_crate_data_in_database( registry_data: &CrateData, ) -> Result<()> { info!("Updating crate data for {}", name); - let crate_id = sqlx::query_scalar!("SELECT id FROM crates WHERE crates.name = $1", name) - .fetch_one(&mut *conn) - .await?; + let crate_id = sqlx::query_scalar!( + r#"SELECT id as "id: CrateId" FROM crates WHERE crates.name = $1"#, + name + ) + .fetch_one(&mut *conn) + .await?; update_owners_in_database(conn, ®istry_data.owners, crate_id).await?; @@ -547,7 +575,7 @@ pub async fn update_crate_data_in_database( async fn update_owners_in_database( conn: &mut sqlx::PgConnection, owners: &[CrateOwner], - crate_id: i32, + crate_id: CrateId, ) -> Result<()> { // Update any existing owner data since it is mutable and could have changed since last // time we pulled it @@ -579,7 +607,7 @@ async fn update_owners_in_database( FROM UNNEST($2::int[]) as oid ON CONFLICT (cid,oid) DO NOTHING", - crate_id, + crate_id.0, &oids[..] ) .execute(&mut *conn) @@ -590,7 +618,7 @@ async fn update_owners_in_database( WHERE cid = $1 AND NOT (oid = ANY($2))", - crate_id, + crate_id.0, &oids[..], ) .execute(&mut *conn) @@ -603,7 +631,7 @@ async fn update_owners_in_database( async fn add_compression_into_database( conn: &mut sqlx::PgConnection, algorithms: I, - release_id: i32, + release_id: ReleaseId, ) -> Result<()> where I: Iterator, @@ -613,7 +641,7 @@ where "INSERT INTO compression_rels (release, algorithm) VALUES ($1, $2) ON CONFLICT DO NOTHING;", - release_id, + release_id.0, &(alg as i32) ) .execute(&mut *conn) @@ -650,7 +678,7 @@ mod test { errors FROM builds WHERE id = $1"#, - build_id + build_id.0 ) .fetch_one(&mut *conn) .await?; @@ -693,7 +721,7 @@ mod test { rustc_nightly_date FROM builds WHERE id = $1"#, - build_id + build_id.0 ) .fetch_one(&mut *conn) .await?; @@ -743,7 +771,7 @@ mod test { rustc_nightly_date FROM builds WHERE id = $1"#, - build_id + build_id.0 ) .fetch_one(&mut *conn) .await?; @@ -787,7 +815,7 @@ mod test { errors FROM builds WHERE id = $1"#, - build_id + build_id.0 ) .fetch_one(&mut *conn) .await?; @@ -824,7 +852,7 @@ mod test { INNER JOIN keyword_rels as kwr on kw.id = kwr.kid WHERE kwr.rid = $1 ORDER BY kw.name,kw.slug"#, - release_id + release_id.0 ) .fetch_all(&mut *conn) .await? @@ -897,7 +925,7 @@ mod test { INNER JOIN keyword_rels as kwr on kw.id = kwr.kid WHERE kwr.rid = $1 ORDER BY kw.name,kw.slug"#, - release_id + release_id.0 ) .fetch_all(&mut *conn) .await? @@ -959,7 +987,7 @@ mod test { WHERE o.id = r.oid AND r.cid = $1", - crate_id + crate_id.0 ) .fetch_one(&mut *conn) .await?; @@ -1008,7 +1036,7 @@ mod test { WHERE o.id = r.oid AND r.cid = $1", - crate_id + crate_id.0 ) .fetch_one(&mut *conn) .await?; @@ -1064,7 +1092,7 @@ mod test { WHERE o.id = r.oid AND r.cid = $1", - crate_id, + crate_id.0, ) .fetch(&mut *conn) .map_ok(|row| row.login) @@ -1143,9 +1171,12 @@ mod test { let name = "krate"; let crate_id = initialize_crate(&mut conn, name).await?; - let id: i32 = sqlx::query_scalar!("SELECT id FROM crates WHERE name = $1", name) - .fetch_one(&mut *conn) - .await?; + let id = sqlx::query_scalar!( + r#"SELECT id as "id: CrateId" FROM crates WHERE name = $1"#, + name + ) + .fetch_one(&mut *conn) + .await?; assert_eq!(crate_id, id); @@ -1166,9 +1197,9 @@ mod test { let release_id = initialize_release(&mut conn, crate_id, version).await?; - let id: i32 = sqlx::query_scalar!( - "SELECT id FROM releases WHERE crate_id = $1 and version = $2", - crate_id, + let id = sqlx::query_scalar!( + r#"SELECT id as "id: ReleaseId" FROM releases WHERE crate_id = $1 and version = $2"#, + crate_id.0, version ) .fetch_one(&mut *conn) @@ -1194,9 +1225,12 @@ mod test { let build_id = initialize_build(&mut conn, release_id).await?; - let id: i32 = sqlx::query_scalar!("SELECT id FROM builds WHERE rid = $1", release_id) - .fetch_one(&mut *conn) - .await?; + let id = sqlx::query_scalar!( + r#"SELECT id as "id: BuildId" FROM builds WHERE rid = $1"#, + release_id.0 + ) + .fetch_one(&mut *conn) + .await?; assert_eq!(build_id, id); @@ -1215,7 +1249,7 @@ mod test { let name: String = "krate".repeat(100); let crate_id = initialize_crate(&mut conn, &name).await?; - let db_name = sqlx::query_scalar!("SELECT name FROM crates WHERE id = $1", crate_id) + let db_name = sqlx::query_scalar!("SELECT name FROM crates WHERE id = $1", crate_id.0) .fetch_one(&mut *conn) .await?; @@ -1235,7 +1269,7 @@ mod test { let release_id = initialize_release(&mut conn, crate_id, &version).await?; let db_version = - sqlx::query_scalar!("SELECT version FROM releases WHERE id = $1", release_id) + sqlx::query_scalar!("SELECT version FROM releases WHERE id = $1", release_id.0) .fetch_one(&mut *conn) .await?; diff --git a/src/db/delete.rs b/src/db/delete.rs index 31a56a650..fc741fc55 100644 --- a/src/db/delete.rs +++ b/src/db/delete.rs @@ -7,7 +7,7 @@ use anyhow::Context as _; use fn_error_context::context; use sqlx::Connection; -use super::update_latest_version_id; +use super::{update_latest_version_id, CrateId}; /// List of directories in docs.rs's underlying storage (either the database or S3) containing a /// subdirectory named after the crate. Those subdirectories will be deleted. @@ -104,9 +104,13 @@ pub async fn delete_version( Ok(()) } -async fn get_id(conn: &mut sqlx::PgConnection, name: &str) -> Result { +async fn get_id(conn: &mut sqlx::PgConnection, name: &str) -> Result { Ok(sqlx::query_scalar!( - "SELECT id FROM crates WHERE normalize_crate_name(name) = normalize_crate_name($1)", + r#" + SELECT id as "id: CrateId" + FROM crates + WHERE normalize_crate_name(name) = normalize_crate_name($1) + "#, name ) .fetch_optional(&mut *conn) @@ -138,7 +142,7 @@ async fn delete_version_from_database( } let is_library: bool = sqlx::query_scalar!( "DELETE FROM releases WHERE crate_id = $1 AND version = $2 RETURNING is_library", - crate_id, + crate_id.0, version, ) .fetch_one(&mut *transaction) @@ -169,7 +173,7 @@ async fn delete_version_from_database( async fn delete_crate_from_database( conn: &mut sqlx::PgConnection, name: &str, - crate_id: i32, + crate_id: CrateId, ) -> Result { let mut transaction = conn.begin().await?; @@ -184,7 +188,7 @@ async fn delete_crate_from_database( ) .as_str()).bind(crate_id).execute(&mut *transaction).await?; } - sqlx::query!("DELETE FROM owner_rels WHERE cid = $1;", crate_id) + sqlx::query!("DELETE FROM owner_rels WHERE cid = $1;", crate_id.0) .execute(&mut *transaction) .await?; @@ -194,16 +198,16 @@ async fn delete_crate_from_database( FROM releases WHERE releases.crate_id = $1 ", - crate_id + crate_id.0 ) .fetch_one(&mut *transaction) .await? .unwrap_or(false); - sqlx::query!("DELETE FROM releases WHERE crate_id = $1;", crate_id) + sqlx::query!("DELETE FROM releases WHERE crate_id = $1;", crate_id.0) .execute(&mut *transaction) .await?; - sqlx::query!("DELETE FROM crates WHERE id = $1;", crate_id) + sqlx::query!("DELETE FROM crates WHERE id = $1;", crate_id.0) .execute(&mut *transaction) .await?; @@ -216,6 +220,7 @@ async fn delete_crate_from_database( #[cfg(test)] mod tests { use super::*; + use crate::db::ReleaseId; use crate::registry_api::{CrateOwner, OwnerKind}; use crate::test::{async_wrapper, fake_release_that_failed_before_build}; use test_case::test_case; @@ -227,8 +232,8 @@ mod tests { .is_some()) } - async fn release_exists(conn: &mut sqlx::PgConnection, id: i32) -> Result { - Ok(sqlx::query!("SELECT id FROM releases WHERE id = $1;", id) + async fn release_exists(conn: &mut sqlx::PgConnection, id: ReleaseId) -> Result { + Ok(sqlx::query!("SELECT id FROM releases WHERE id = $1;", id.0) .fetch_optional(conn) .await? .is_some()) @@ -298,7 +303,7 @@ mod tests { .rustdoc_file_exists( pkg, version, - 0, + None, &format!("{pkg}/index.html"), archive_storage ) @@ -327,7 +332,7 @@ mod tests { .rustdoc_file_exists( "package-2", "1.0.0", - 0, + None, "package-2/index.html", archive_storage ) @@ -355,7 +360,7 @@ mod tests { .rustdoc_file_exists( "package-1", "1.0.0", - 0, + None, "package-1/index.html", archive_storage ) @@ -367,7 +372,7 @@ mod tests { .rustdoc_file_exists( "package-1", "2.0.0", - 0, + None, "package-1/index.html", archive_storage ) @@ -383,12 +388,15 @@ mod tests { #[test_case(false)] fn test_delete_version(archive_storage: bool) { async_wrapper(|env| async move { - async fn owners(conn: &mut sqlx::PgConnection, crate_id: i32) -> Result> { + async fn owners( + conn: &mut sqlx::PgConnection, + crate_id: CrateId, + ) -> Result> { Ok(sqlx::query!( "SELECT login FROM owners INNER JOIN owner_rels ON owners.id = owner_rels.oid WHERE owner_rels.cid = $1", - crate_id, + crate_id.0, ) .fetch_all(conn) .await? @@ -415,12 +423,15 @@ mod tests { assert!( env.async_storage() .await - .rustdoc_file_exists("a", "1.0.0", 0, "a/index.html", archive_storage) + .rustdoc_file_exists("a", "1.0.0", None, "a/index.html", archive_storage) .await? ); - let crate_id = sqlx::query_scalar!("SELECT crate_id FROM releases WHERE id = $1", v1) - .fetch_one(&mut *conn) - .await?; + let crate_id = sqlx::query_scalar!( + r#"SELECT crate_id as "crate_id: CrateId" FROM releases WHERE id = $1"#, + v1.0 + ) + .fetch_one(&mut *conn) + .await?; assert_eq!( owners(&mut conn, crate_id).await?, vec!["malicious actor".to_string()] @@ -443,7 +454,7 @@ mod tests { assert!( env.async_storage() .await - .rustdoc_file_exists("a", "2.0.0", 0, "a/index.html", archive_storage) + .rustdoc_file_exists("a", "2.0.0", None, "a/index.html", archive_storage) .await? ); assert_eq!( @@ -478,7 +489,7 @@ mod tests { assert!( !env.async_storage() .await - .rustdoc_file_exists("a", "1.0.0", 0, "a/index.html", archive_storage) + .rustdoc_file_exists("a", "1.0.0", None, "a/index.html", archive_storage) .await? ); } @@ -486,7 +497,7 @@ mod tests { assert!( env.async_storage() .await - .rustdoc_file_exists("a", "2.0.0", 0, "a/index.html", archive_storage) + .rustdoc_file_exists("a", "2.0.0", None, "a/index.html", archive_storage) .await? ); assert_eq!( diff --git a/src/db/mod.rs b/src/db/mod.rs index 5538903e3..f6db7fe27 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -8,7 +8,9 @@ pub(crate) use self::add_package::{ initialize_release, update_build_with_error, }; pub use self::{ - add_package::{update_build_status, update_crate_data_in_database}, + add_package::{ + update_build_status, update_crate_data_in_database, BuildId, CrateId, ReleaseId, + }, delete::{delete_crate, delete_version}, file::{add_path_into_database, add_path_into_remote_archive}, overrides::Overrides, diff --git a/src/docbuilder/rustwide_builder.rs b/src/docbuilder/rustwide_builder.rs index b20a8f662..868d24980 100644 --- a/src/docbuilder/rustwide_builder.rs +++ b/src/docbuilder/rustwide_builder.rs @@ -1,9 +1,12 @@ -use crate::db::file::{add_path_into_database, file_list_to_json}; use crate::db::{ add_doc_coverage, add_package_into_database, add_path_into_remote_archive, finish_build, initialize_build, initialize_crate, initialize_release, types::BuildStatus, update_build_with_error, update_crate_data_in_database, Pool, }; +use crate::db::{ + file::{add_path_into_database, file_list_to_json}, + BuildId, +}; use crate::docbuilder::Limits; use crate::error::Result; use crate::repositories::RepositoryStatsUpdater; @@ -362,7 +365,7 @@ impl RustwideBuilder { let crate_id = initialize_crate(&mut conn, name).await?; let release_id = initialize_release(&mut conn, crate_id, version).await?; let build_id = initialize_build(&mut conn, release_id).await?; - Ok::(build_id) + Ok::(build_id) })?; match self.build_package_inner(name, version, kind, build_id) { @@ -392,7 +395,7 @@ impl RustwideBuilder { name: &str, version: &str, kind: PackageKind<'_>, - build_id: i32, + build_id: BuildId, ) -> Result { info!("building package {} {}", name, version); @@ -1163,18 +1166,18 @@ mod tests { // default target was built and is accessible assert!(storage.exists_in_archive( &doc_archive, - 0, + None, &format!("{crate_path}/index.html"), )?); assert_success(&format!("/{crate_}/{version}/{crate_path}"), web)?; // source is also packaged - assert!(storage.exists_in_archive(&source_archive, 0, "src/lib.rs",)?); + assert!(storage.exists_in_archive(&source_archive, None, "src/lib.rs",)?); assert_success(&format!("/crate/{crate_}/{version}/source/src/lib.rs"), web)?; assert!(!storage.exists_in_archive( &doc_archive, - 0, + None, &format!("{default_target}/{crate_path}/index.html"), )?); @@ -1208,7 +1211,7 @@ mod tests { } let target_docs_present = storage.exists_in_archive( &doc_archive, - 0, + None, &format!("{target}/{crate_path}/index.html"), )?; @@ -1349,7 +1352,7 @@ mod tests { let crate_path = crate_.replace('-', "_"); let target_docs_present = storage.exists_in_archive( &doc_archive, - 0, + None, &format!("{target}/{crate_path}/index.html"), )?; diff --git a/src/metrics/mod.rs b/src/metrics/mod.rs index 5035b4bc4..d6ff4d84b 100644 --- a/src/metrics/mod.rs +++ b/src/metrics/mod.rs @@ -2,7 +2,12 @@ mod macros; use self::macros::MetricFromOpts; -use crate::{cdn, db::Pool, target::TargetAtom, AsyncBuildQueue, Config}; +use crate::{ + cdn, + db::{CrateId, Pool, ReleaseId}, + target::TargetAtom, + AsyncBuildQueue, Config, +}; use anyhow::Error; use dashmap::DashMap; use prometheus::proto::MetricFamily; @@ -145,9 +150,9 @@ pub(crate) fn duration_to_seconds(d: Duration) -> f64 { #[derive(Debug, Default)] pub(crate) struct RecentlyAccessedReleases { - crates: DashMap, - versions: DashMap, - platforms: DashMap<(i32, TargetAtom), Instant>, + crates: DashMap, + versions: DashMap, + platforms: DashMap<(ReleaseId, TargetAtom), Instant>, } impl RecentlyAccessedReleases { @@ -155,7 +160,7 @@ impl RecentlyAccessedReleases { Self::default() } - pub(crate) fn record(&self, krate: i32, version: i32, target: &str) { + pub(crate) fn record(&self, krate: CrateId, version: ReleaseId, target: &str) { if self.platforms.len() > 100_000 { // Avoid filling the maps _too_ much, we should never get anywhere near this limit return; diff --git a/src/storage/mod.rs b/src/storage/mod.rs index ade5a6090..cbb30cde4 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -9,7 +9,7 @@ use self::s3::S3Backend; use crate::{ db::{ file::{detect_mime, FileEntry}, - mimes, Pool, + mimes, BuildId, Pool, }, error::Result, utils::spawn_blocking, @@ -187,7 +187,7 @@ impl AsyncStorage { &self, name: &str, version: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, archive_storage: bool, ) -> Result { @@ -212,7 +212,7 @@ impl AsyncStorage { &self, name: &str, version: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, archive_storage: bool, ) -> Result { @@ -235,7 +235,7 @@ impl AsyncStorage { &self, name: &str, version: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, archive_storage: bool, ) -> Result { @@ -253,7 +253,7 @@ impl AsyncStorage { pub(crate) async fn exists_in_archive( &self, archive_path: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, ) -> Result { match self @@ -316,14 +316,14 @@ impl AsyncStorage { pub(super) async fn download_archive_index( &self, archive_path: &str, - latest_build_id: i32, + latest_build_id: Option, ) -> Result { // remote/folder/and/x.zip.index let remote_index_path = format!("{archive_path}.index"); - let local_index_path = self - .config - .local_archive_cache_path - .join(format!("{archive_path}.{latest_build_id}.index")); + let local_index_path = self.config.local_archive_cache_path.join(format!( + "{archive_path}.{}.index", + latest_build_id.map(|id| id.0).unwrap_or(0) + )); if !local_index_path.exists() { let index_content = self.get(&remote_index_path, usize::MAX).await?.content; @@ -353,7 +353,7 @@ impl AsyncStorage { pub(crate) async fn get_from_archive( &self, archive_path: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, max_size: usize, ) -> Result { @@ -640,7 +640,7 @@ impl Storage { &self, name: &str, version: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, archive_storage: bool, ) -> Result { @@ -657,7 +657,7 @@ impl Storage { &self, name: &str, version: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, archive_storage: bool, ) -> Result { @@ -674,7 +674,7 @@ impl Storage { &self, name: &str, version: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, archive_storage: bool, ) -> Result { @@ -690,7 +690,7 @@ impl Storage { pub(crate) fn exists_in_archive( &self, archive_path: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, ) -> Result { self.runtime.block_on( @@ -717,7 +717,7 @@ impl Storage { pub(super) fn download_index( &self, archive_path: &str, - latest_build_id: i32, + latest_build_id: Option, ) -> Result { self.runtime.block_on( self.inner @@ -728,7 +728,7 @@ impl Storage { pub(crate) fn get_from_archive( &self, archive_path: &str, - latest_build_id: i32, + latest_build_id: Option, path: &str, max_size: usize, ) -> Result { @@ -1102,7 +1102,7 @@ mod backend_tests { fn test_exists_without_remote_archive(storage: &Storage) -> Result<()> { // when remote and local index don't exist, any `exists_in_archive` should // return `false` - assert!(!storage.exists_in_archive("some_archive_name", 0, "some_file_name")?); + assert!(!storage.exists_in_archive("some_archive_name", None, "some_file_name")?); Ok(()) } @@ -1151,18 +1151,18 @@ mod backend_tests { // the first exists-query will download and store the index assert!(!local_index_location.exists()); - assert!(storage.exists_in_archive("folder/test.zip", 0, "Cargo.toml",)?); + assert!(storage.exists_in_archive("folder/test.zip", None, "Cargo.toml",)?); // the second one will use the local index assert!(local_index_location.exists()); - assert!(storage.exists_in_archive("folder/test.zip", 0, "src/main.rs",)?); + assert!(storage.exists_in_archive("folder/test.zip", None, "src/main.rs",)?); - let file = storage.get_from_archive("folder/test.zip", 0, "Cargo.toml", usize::MAX)?; + let file = storage.get_from_archive("folder/test.zip", None, "Cargo.toml", usize::MAX)?; assert_eq!(file.content, b"data"); assert_eq!(file.mime, "text/toml"); assert_eq!(file.path, "folder/test.zip/Cargo.toml"); - let file = storage.get_from_archive("folder/test.zip", 0, "src/main.rs", usize::MAX)?; + let file = storage.get_from_archive("folder/test.zip", None, "src/main.rs", usize::MAX)?; assert_eq!(file.content, b"data"); assert_eq!(file.mime, "text/rust"); assert_eq!(file.path, "folder/test.zip/src/main.rs"); diff --git a/src/test/fakes.rs b/src/test/fakes.rs index eb790e86f..bea2a0ae0 100644 --- a/src/test/fakes.rs +++ b/src/test/fakes.rs @@ -2,7 +2,9 @@ use super::TestDatabase; use crate::db::file::{file_list_to_json, FileEntry}; use crate::db::types::BuildStatus; -use crate::db::{initialize_build, initialize_crate, initialize_release, update_build_status}; +use crate::db::{ + initialize_build, initialize_crate, initialize_release, update_build_status, BuildId, ReleaseId, +}; use crate::docbuilder::DocCoverage; use crate::error::Result; use crate::registry_api::{CrateData, CrateOwner, ReleaseData}; @@ -27,7 +29,7 @@ pub(crate) async fn fake_release_that_failed_before_build( name: &str, version: &str, errors: &str, -) -> Result<(i32, i32)> { +) -> Result<(ReleaseId, BuildId)> { let crate_id = initialize_crate(&mut *conn, name).await?; let release_id = initialize_release(&mut *conn, crate_id, version).await?; let build_id = initialize_build(&mut *conn, release_id).await?; @@ -38,7 +40,7 @@ pub(crate) async fn fake_release_that_failed_before_build( build_status = 'failure', errors = $2 WHERE id = $1", - build_id, + build_id.0, errors, ) .execute(&mut *conn) @@ -326,13 +328,13 @@ impl<'a> FakeRelease<'a> { self } - pub(crate) fn create(self) -> Result { + pub(crate) fn create(self) -> Result { let runtime = self.runtime.clone(); runtime.block_on(self.create_async()) } /// Returns the release_id - pub(crate) async fn create_async(self) -> Result { + pub(crate) async fn create_async(self) -> Result { use std::fs; use std::path::Path; @@ -645,7 +647,7 @@ impl FakeBuild { &self, conn: &mut sqlx::PgConnection, storage: &AsyncStorage, - release_id: i32, + release_id: ReleaseId, default_target: &str, ) -> Result<()> { let build_id = crate::db::initialize_build(&mut *conn, release_id).await?; @@ -664,7 +666,7 @@ impl FakeBuild { if let Some(db_build_log) = self.db_build_log.as_deref() { sqlx::query!( "UPDATE builds SET output = $2 WHERE id = $1", - build_id, + build_id.0, db_build_log ) .execute(&mut *conn) diff --git a/src/web/build_details.rs b/src/web/build_details.rs index e5f648408..9888ebaf5 100644 --- a/src/web/build_details.rs +++ b/src/web/build_details.rs @@ -1,5 +1,5 @@ use crate::{ - db::types::BuildStatus, + db::{types::BuildStatus, BuildId}, impl_axum_webpage, web::{ error::{AxumNope, AxumResult}, @@ -22,7 +22,7 @@ use std::sync::Arc; #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct BuildDetails { - id: i32, + id: BuildId, rustc_version: Option, docsrs_version: Option, build_status: BuildStatus, @@ -65,7 +65,11 @@ pub(crate) async fn build_details_handler( Extension(config): Extension>, Extension(storage): Extension>, ) -> AxumResult { - let id: i32 = params.id.parse().map_err(|_| AxumNope::BuildNotFound)?; + let id = params + .id + .parse() + .map(BuildId) + .map_err(|_| AxumNope::BuildNotFound)?; let row = sqlx::query!( r#"SELECT @@ -80,7 +84,7 @@ pub(crate) async fn build_details_handler( INNER JOIN releases ON releases.id = builds.rid INNER JOIN crates ON releases.crate_id = crates.id WHERE builds.id = $1 AND crates.name = $2 AND releases.version = $3"#, - id, + id.0, params.name, params.version.to_string(), ) diff --git a/src/web/builds.rs b/src/web/builds.rs index 8c99f6f5b..74cc5d132 100644 --- a/src/web/builds.rs +++ b/src/web/builds.rs @@ -4,7 +4,7 @@ use super::{ headers::CanonicalUrl, }; use crate::{ - db::types::BuildStatus, + db::{types::BuildStatus, BuildId}, docbuilder::Limits, impl_axum_webpage, web::{ @@ -33,7 +33,7 @@ use std::sync::Arc; #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct Build { - id: i32, + id: BuildId, rustc_version: Option, docsrs_version: Option, build_status: BuildStatus, @@ -230,7 +230,7 @@ async fn get_builds( Ok(sqlx::query_as!( Build, r#"SELECT - builds.id, + builds.id as "id: BuildId", builds.rustc_version, builds.docsrs_version, builds.build_status as "build_status: BuildStatus", @@ -242,7 +242,7 @@ async fn get_builds( WHERE crates.name = $1 AND releases.version = $2 - ORDER BY id DESC"#, + ORDER BY builds.id DESC"#, name, version.to_string(), ) diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 4606d7eed..50b2f15c0 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -1,8 +1,9 @@ use super::{match_version, MetaData}; +use crate::db::{BuildId, ReleaseId}; use crate::registry_api::OwnerKind; use crate::utils::{get_correct_docsrs_style_file, report_error}; use crate::{ - db::types::BuildStatus, + db::{types::BuildStatus, CrateId}, impl_axum_webpage, storage::PathNotFoundError, web::{ @@ -42,7 +43,7 @@ pub(crate) struct CrateDetails { rustdoc: Option, // this is description_long in database release_time: Option>, build_status: BuildStatus, - pub latest_build_id: Option, + pub latest_build_id: Option, last_successful_build: Option, pub rustdoc_status: Option, pub archive_storage: bool, @@ -62,9 +63,9 @@ pub(crate) struct CrateDetails { pub(crate) total_items_needing_examples: Option, pub(crate) items_with_examples: Option, /// Database id for this crate - pub(crate) crate_id: i32, + pub(crate) crate_id: CrateId, /// Database id for this release - pub(crate) release_id: i32, + pub(crate) release_id: ReleaseId, source_size: Option, documentation_size: Option, } @@ -79,7 +80,7 @@ struct RepositoryMetadata { #[derive(Debug, Clone, Eq, PartialEq)] pub(crate) struct Release { - pub id: i32, + pub id: ReleaseId, pub version: semver::Version, /// Aggregated build status of the release. /// * no builds -> build In progress @@ -126,8 +127,8 @@ impl CrateDetails { ) -> Result, anyhow::Error> { let krate = match sqlx::query!( r#"SELECT - crates.id AS crate_id, - releases.id AS release_id, + crates.id AS "crate_id: CrateId", + releases.id AS "release_id: ReleaseId", crates.name, releases.version, releases.description, @@ -138,7 +139,7 @@ impl CrateDetails { release_build_status.build_status as "build_status!: BuildStatus", -- this is the latest build ID that generated content -- it's used to invalidate some blob storage related caches. - builds.id as "latest_build_id?", + builds.id as "latest_build_id?: BuildId", releases.rustdoc_status, releases.archive_storage, releases.repository_url, @@ -265,7 +266,7 @@ impl CrateDetails { FROM owners INNER JOIN owner_rels ON owner_rels.oid = owners.id WHERE cid = $1"#, - krate.crate_id, + krate.crate_id.0, ) .fetch(&mut *conn) .map_ok(|row| (row.login, row.avatar, row.kind)) @@ -292,7 +293,7 @@ impl CrateDetails { .fetch_source_file( &self.name, &self.version.to_string(), - self.latest_build_id.unwrap_or(0), + self.latest_build_id, "Cargo.toml", self.archive_storage, ) @@ -321,7 +322,7 @@ impl CrateDetails { .fetch_source_file( &self.name, &self.version.to_string(), - self.latest_build_id.unwrap_or(0), + self.latest_build_id, path, self.archive_storage, ) @@ -367,11 +368,11 @@ pub(crate) fn latest_release(releases: &[Release]) -> Option<&Release> { /// Return all releases for a crate, sorted in descending order by semver pub(crate) async fn releases_for_crate( conn: &mut sqlx::PgConnection, - crate_id: i32, + crate_id: CrateId, ) -> Result, anyhow::Error> { let mut releases: Vec = sqlx::query!( r#"SELECT - releases.id, + releases.id as "id: ReleaseId", releases.version, release_build_status.build_status as "build_status!: BuildStatus", releases.yanked, @@ -382,7 +383,7 @@ pub(crate) async fn releases_for_crate( INNER JOIN release_build_status ON releases.id = release_build_status.rid WHERE releases.crate_id = $1"#, - crate_id, + crate_id.0, ) .fetch(&mut *conn) .try_filter_map(|row| async move { @@ -596,7 +597,7 @@ pub(crate) async fn get_all_releases( releases.doc_targets FROM releases WHERE releases.id = $1;", - matched_release.id(), + matched_release.id().0, ) .fetch_optional(&mut *conn) .await? @@ -721,7 +722,7 @@ pub(crate) async fn get_all_platforms_inner( releases.doc_targets FROM releases WHERE releases.id = $1;", - matched_release.id(), + matched_release.id().0, ) .fetch_optional(&mut *conn) .await? @@ -867,10 +868,13 @@ mod tests { version: &str, req_version: Option, ) -> CrateDetails { - let crate_id: i32 = sqlx::query_scalar!("SELECT id FROM crates WHERE name = $1", name) - .fetch_one(&mut *conn) - .await - .unwrap(); + let crate_id = sqlx::query_scalar!( + r#"SELECT id as "id: CrateId" FROM crates WHERE name = $1"#, + name + ) + .fetch_one(&mut *conn) + .await + .unwrap(); let releases = releases_for_crate(&mut *conn, crate_id).await.unwrap(); @@ -1688,7 +1692,7 @@ mod tests { env.runtime().block_on(async { let mut conn = env.async_db().await.async_conn().await; - sqlx::query!("UPDATE releases SET features = NULL WHERE id = $1", id) + sqlx::query!("UPDATE releases SET features = NULL WHERE id = $1", id.0) .execute(&mut *conn) .await })?; diff --git a/src/web/mod.rs b/src/web/mod.rs index 8ce5832ce..b6720ead2 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -4,6 +4,8 @@ pub mod page; // mod tmp; use crate::db::types::BuildStatus; +use crate::db::CrateId; +use crate::db::ReleaseId; use crate::utils::get_correct_docsrs_style_file; use crate::utils::report_error; use crate::web::page::templates::{filters, RenderSolid}; @@ -215,7 +217,7 @@ impl MatchedRelease { &self.release.version } - fn id(&self) -> i32 { + fn id(&self) -> ReleaseId { self.release.id } @@ -275,9 +277,12 @@ async fn match_version( ) -> Result { let (crate_id, corrected_name) = { let row = sqlx::query!( - "SELECT id, name + r#" + SELECT + id as "id: CrateId", + name FROM crates - WHERE normalize_crate_name(name) = normalize_crate_name($1)", + WHERE normalize_crate_name(name) = normalize_crate_name($1)"#, name, ) .fetch_optional(&mut *conn) @@ -762,12 +767,12 @@ impl_axum_webpage! { #[cfg(test)] mod test { use super::*; - use crate::{docbuilder::DocCoverage, test::*}; + use crate::{db::ReleaseId, docbuilder::DocCoverage, test::*}; use kuchikiki::traits::TendrilSink; use serde_json::json; use test_case::test_case; - async fn release(version: &str, env: &TestEnvironment) -> i32 { + async fn release(version: &str, env: &TestEnvironment) -> ReleaseId { env.async_fake_release() .await .name("foo") @@ -1057,7 +1062,7 @@ mod test { sqlx::query!( "UPDATE releases SET yanked = true WHERE id = $1 AND version = '0.3.0'", - release_id + release_id.0 ) .execute(&mut *db.async_conn().await) .await?; diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index 7a0d5c7d4..002380256 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -14,8 +14,10 @@ use crate::{ extractors::{DbConnection, Path}, file::File, match_version, - page::templates::{filters, RenderRegular, RenderSolid}, - page::TemplateData, + page::{ + templates::{filters, RenderRegular, RenderSolid}, + TemplateData, + }, MetaData, ReqVersion, }, AsyncStorage, Config, InstanceMetrics, RUSTDOC_STATIC_STORAGE_PREFIX, @@ -180,7 +182,7 @@ pub(crate) async fn rustdoc_redirector_handler( .fetch_rustdoc_file( &crate_name, &krate.version.to_string(), - krate.latest_build_id.unwrap_or(0), + krate.latest_build_id, target, krate.archive_storage, ) @@ -457,7 +459,7 @@ pub(crate) async fn rustdoc_html_server_handler( .fetch_rustdoc_file( ¶ms.name, &krate.version.to_string(), - krate.latest_build_id.unwrap_or(0), + krate.latest_build_id, &storage_path, krate.archive_storage, ) @@ -478,7 +480,7 @@ pub(crate) async fn rustdoc_html_server_handler( .rustdoc_file_exists( ¶ms.name, &krate.version.to_string(), - krate.latest_build_id.unwrap_or(0), + krate.latest_build_id, &storage_path, krate.archive_storage, ) @@ -747,7 +749,7 @@ pub(crate) async fn target_redirect_handler( .rustdoc_file_exists( &name, &crate_details.version.to_string(), - crate_details.latest_build_id.unwrap_or(0), + crate_details.latest_build_id, &storage_location_for_path, crate_details.archive_storage, ) @@ -2051,7 +2053,7 @@ mod test { let mut conn = env.async_db().await.async_conn().await; // https://stackoverflow.com/questions/18209625/how-do-i-modify-fields-inside-the-new-postgresql-json-datatype sqlx::query!( - r#"UPDATE releases SET dependencies = dependencies::jsonb #- '{0,2}' WHERE id = $1"#, id) + r#"UPDATE releases SET dependencies = dependencies::jsonb #- '{0,2}' WHERE id = $1"#, id.0) .execute(&mut *conn) .await })?; diff --git a/src/web/source.rs b/src/web/source.rs index 8c361c217..dc8887170 100644 --- a/src/web/source.rs +++ b/src/web/source.rs @@ -1,6 +1,6 @@ use super::{error::AxumResult, match_version}; use crate::{ - db::Pool, + db::{BuildId, Pool}, impl_axum_webpage, storage::PathNotFoundError, web::{ @@ -220,7 +220,7 @@ pub(crate) async fn source_browser_handler( .into_version(); let row = sqlx::query!( - "SELECT + r#"SELECT releases.archive_storage, ( SELECT id @@ -230,12 +230,12 @@ pub(crate) async fn source_browser_handler( builds.build_status = 'success' ORDER BY build_finished DESC LIMIT 1 - ) AS latest_build_id + ) AS "latest_build_id?: BuildId" FROM releases INNER JOIN crates ON releases.crate_id = crates.id WHERE name = $1 AND - version = $2", + version = $2"#, params.name, version.to_string() ) @@ -249,7 +249,7 @@ pub(crate) async fn source_browser_handler( .fetch_source_file( ¶ms.name, &version.to_string(), - row.latest_build_id.unwrap_or(0), + row.latest_build_id, ¶ms.path, row.archive_storage, ) @@ -501,7 +501,7 @@ mod tests { "UPDATE releases SET files = NULL WHERE id = $1", - release_id, + release_id.0, ) .execute(&mut *conn) .await