@@ -133,7 +133,11 @@ fn list_by_date(
133133
134134 Ok ( PaginatedVersionsAndPublishers {
135135 data,
136- meta : ResponseMeta { total, next_page } ,
136+ meta : ResponseMeta {
137+ total,
138+ next_page,
139+ release_tracks : None ,
140+ } ,
137141 } )
138142}
139143
@@ -153,7 +157,7 @@ fn list_by_semver(
153157) -> AppResult < PaginatedVersionsAndPublishers > {
154158 use seek:: * ;
155159
156- let ( data, total) = if let Some ( options) = options {
160+ let ( data, total, release_tracks ) = if let Some ( options) = options {
157161 // Since versions will only increase in the future and both sorting and pagination need to
158162 // happen on the app server, implementing it with fetching only the data needed for sorting
159163 // and pagination, then making another query for the data to respond with, would minimize
@@ -164,18 +168,26 @@ fn list_by_semver(
164168 let mut sorted_versions = IndexMap :: new ( ) ;
165169 for result in versions:: table
166170 . filter ( versions:: crate_id. eq ( crate_id) )
167- . select ( ( versions:: id, versions:: num) )
168- . load_iter :: < ( i32 , String ) , DefaultLoadingMode > ( conn) ?
171+ . select ( ( versions:: id, versions:: num, versions :: yanked ) )
172+ . load_iter :: < ( i32 , String , bool ) , DefaultLoadingMode > ( conn) ?
169173 {
170- let ( id, num) = result?;
171- sorted_versions. insert ( id, ( num, None ) ) ;
174+ let ( id, num, yanked) = result?;
175+ let semver = semver:: Version :: parse ( & num) . ok ( ) ;
176+ sorted_versions. insert ( id, ( semver, yanked, None ) ) ;
172177 }
173- sorted_versions. sort_by_cached_key ( |_, ( num, _) | Reverse ( semver:: Version :: parse ( num) . ok ( ) ) ) ;
178+ sorted_versions
179+ . sort_unstable_by ( |_, ( semver_a, _, _) , _, ( semver_b, _, _) | semver_b. cmp ( semver_a) ) ;
174180
175181 assert ! (
176182 !matches!( & options. page, Page :: Numeric ( _) ) ,
177183 "?page= is not supported"
178184 ) ;
185+ let release_tracks = Some ( ReleaseTracks :: from_sorted_semver_iter (
186+ sorted_versions
187+ . values ( )
188+ . filter ( |( _, yanked, _) | !yanked)
189+ . filter_map ( |( semver, _, _) | semver. as_ref ( ) ) ,
190+ ) ) ;
179191 let mut idx = Some ( 0 ) ;
180192 if let Some ( SeekPayload :: Semver ( Semver { id } ) ) = Seek :: Semver . after ( & options. page ) ? {
181193 idx = sorted_versions
@@ -197,19 +209,24 @@ fn list_by_semver(
197209 . load_iter :: < ( Version , Option < User > ) , DefaultLoadingMode > ( conn) ?
198210 {
199211 let row = result?;
200- sorted_versions. insert ( row. 0 . id , ( row. 0 . num . to_owned ( ) , Some ( row) ) ) ;
212+ // The versions are already sorted, and we only need to enrich the fetched rows into them.
213+ // Therefore, other values can now be safely ignored.
214+ sorted_versions
215+ . entry ( row. 0 . id )
216+ . and_modify ( |entry| * entry = ( None , false , Some ( row) ) ) ;
201217 }
202218
203219 let len = sorted_versions. len ( ) ;
204220 (
205221 sorted_versions
206222 . into_values ( )
207- . filter_map ( |( _, v) | v)
223+ . filter_map ( |( _, _ , v) | v)
208224 . collect ( ) ,
209225 len,
226+ release_tracks,
210227 )
211228 } else {
212- ( vec ! [ ] , 0 )
229+ ( vec ! [ ] , 0 , release_tracks )
213230 }
214231 } else {
215232 let mut data: Vec < ( Version , Option < User > ) > = versions:: table
@@ -219,7 +236,7 @@ fn list_by_semver(
219236 . load ( conn) ?;
220237 data. sort_by_cached_key ( |( version, _) | Reverse ( semver:: Version :: parse ( & version. num ) . ok ( ) ) ) ;
221238 let total = data. len ( ) ;
222- ( data, total)
239+ ( data, total, None )
223240 } ;
224241
225242 let mut next_page = None ;
@@ -233,6 +250,7 @@ fn list_by_semver(
233250 meta : ResponseMeta {
234251 total : total as i64 ,
235252 next_page,
253+ release_tracks,
236254 } ,
237255 } )
238256}
@@ -302,6 +320,7 @@ struct PaginatedVersionsAndPublishers {
302320struct ResponseMeta {
303321 total : i64 ,
304322 next_page : Option < String > ,
323+ release_tracks : Option < ReleaseTracks > ,
305324}
306325
307326#[ derive( Debug , Eq , PartialEq , Serialize ) ]
0 commit comments