@@ -6,11 +6,10 @@ use crates_io::worker::jobs;
66use crates_io:: { db, schema:: crates} ;
77use crates_io_worker:: BackgroundJob ;
88use diesel:: dsl:: sql;
9+ use diesel:: expression:: SqlLiteral ;
10+ use diesel:: prelude:: * ;
911use diesel:: sql_types:: { Array , BigInt , Text } ;
10- use diesel:: { ExpressionMethods , QueryDsl } ;
1112use diesel_async:: RunQueryDsl ;
12- use futures_util:: TryStreamExt ;
13- use std:: collections:: HashMap ;
1413use std:: fmt:: Display ;
1514
1615#[ derive( clap:: Parser , Debug ) ]
@@ -40,56 +39,15 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> {
4039 let existing_crates = crates:: table
4140 . inner_join ( crate_downloads:: table)
4241 . filter ( crates:: name. eq_any ( & crate_names) )
43- . select ( (
44- crates:: name,
45- crates:: id,
46- crate_downloads:: downloads,
47- sql :: < Array < Text > > (
48- r#"
49- ARRAY(
50- SELECT
51- CASE WHEN crate_owners.owner_kind = 1 THEN
52- teams.login
53- ELSE
54- users.gh_login
55- END
56- FROM crate_owners
57- LEFT JOIN teams ON teams.id = crate_owners.owner_id
58- LEFT JOIN users ON users.id = crate_owners.owner_id
59- WHERE crate_owners.crate_id = crates.id
60- )
61- "# ,
62- ) ,
63- sql :: < BigInt > (
64- // This is an incorrect reverse dependencies query, since it
65- // includes the `dependencies` rows for all versions, not just
66- // the "default version" per crate. However, it's good enough
67- // for our purposes here.
68- r#"
69- (
70- SELECT COUNT(*)
71- FROM dependencies
72- WHERE dependencies.crate_id = crates.id
73- )
74- "# ,
75- ) ,
76- ) )
77- . load_stream :: < ( String , i32 , i64 , Vec < String > , i64 ) > ( & mut conn)
42+ . select ( CrateInfo :: as_select ( ) )
43+ . load :: < CrateInfo > ( & mut conn)
7844 . await
79- . context ( "Failed to look up crate name from the database" ) ?
80- . try_fold (
81- HashMap :: new ( ) ,
82- |mut map, ( name, id, downloads, owners, rev_deps) | {
83- map. insert ( name, CrateInfo :: new ( id, downloads, owners, rev_deps) ) ;
84- futures_util:: future:: ready ( Ok ( map) )
85- } ,
86- )
87- . await ?;
45+ . context ( "Failed to look up crate name from the database" ) ?;
8846
8947 println ! ( "Deleting the following crates:" ) ;
9048 println ! ( ) ;
9149 for name in & crate_names {
92- match existing_crates. get ( name) {
50+ match existing_crates. iter ( ) . find ( |info| info . name == * name) {
9351 Some ( info) => println ! ( " - {} ({info})" , name. bold( ) ) ,
9452 None => println ! ( " - {name} (⚠️ crate not found)" ) ,
9553 }
@@ -103,7 +61,7 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> {
10361 }
10462
10563 for name in & crate_names {
106- if let Some ( crate_info) = existing_crates. get ( name) {
64+ if let Some ( crate_info) = existing_crates. iter ( ) . find ( |info| info . name == * name) {
10765 let id = crate_info. id ;
10866
10967 info ! ( "{name}: Deleting crate from the database…" ) ;
@@ -138,25 +96,20 @@ pub async fn run(opts: Opts) -> anyhow::Result<()> {
13896 Ok ( ( ) )
13997}
14098
141- #[ derive( Debug , Clone ) ]
99+ #[ derive( Debug , Clone , Queryable , Selectable ) ]
142100struct CrateInfo {
101+ #[ diesel( select_expression = crates:: columns:: name) ]
102+ name : String ,
103+ #[ diesel( select_expression = crates:: columns:: id) ]
143104 id : i32 ,
105+ #[ diesel( select_expression = crate_downloads:: columns:: downloads) ]
144106 downloads : i64 ,
107+ #[ diesel( select_expression = owners_subquery( ) ) ]
145108 owners : Vec < String > ,
109+ #[ diesel( select_expression = rev_deps_subquery( ) ) ]
146110 rev_deps : i64 ,
147111}
148112
149- impl CrateInfo {
150- pub fn new ( id : i32 , downloads : i64 , owners : Vec < String > , rev_deps : i64 ) -> Self {
151- Self {
152- id,
153- downloads,
154- owners,
155- rev_deps,
156- }
157- }
158- }
159-
160113impl Display for CrateInfo {
161114 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
162115 let id = self . id ;
@@ -175,3 +128,39 @@ impl Display for CrateInfo {
175128 Ok ( ( ) )
176129 }
177130}
131+
132+ /// A subquery that returns the owners of a crate as an array of strings.
133+ #[ diesel:: dsl:: auto_type]
134+ fn owners_subquery ( ) -> SqlLiteral < Array < Text > > {
135+ sql ( r#"
136+ ARRAY(
137+ SELECT
138+ CASE WHEN crate_owners.owner_kind = 1 THEN
139+ teams.login
140+ ELSE
141+ users.gh_login
142+ END
143+ FROM crate_owners
144+ LEFT JOIN teams ON teams.id = crate_owners.owner_id
145+ LEFT JOIN users ON users.id = crate_owners.owner_id
146+ WHERE crate_owners.crate_id = crates.id
147+ )
148+ "# )
149+ }
150+
151+ /// A subquery that returns the number of reverse dependencies of a crate.
152+ ///
153+ /// **Warning:** this is an incorrect reverse dependencies query, since it
154+ /// includes the `dependencies` rows for all versions, not just the
155+ /// "default version" per crate. However, it's good enough for our
156+ /// purposes here.
157+ #[ diesel:: dsl:: auto_type]
158+ fn rev_deps_subquery ( ) -> SqlLiteral < BigInt > {
159+ sql ( r#"
160+ (
161+ SELECT COUNT(*)
162+ FROM dependencies
163+ WHERE dependencies.crate_id = crates.id
164+ )
165+ "# )
166+ }
0 commit comments