Skip to content

Commit 780dae1

Browse files
authored
Merge pull request #10581 from eth3lbert/expose-num-versions
Expose `num_versions` column on the API
2 parents 2def8b2 + c423ac1 commit 780dae1

File tree

36 files changed

+78
-20
lines changed

36 files changed

+78
-20
lines changed

app/components/crate-header.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
</nav.Tab>
5555

5656
<nav.Tab @link={{link "crate.versions" @crate}} data-test-versions-tab>
57-
{{pluralize @crate.versions.length "Version"}}
57+
{{pluralize @crate.num_versions "Version"}}
5858
</nav.Tab>
5959

6060
<nav.Tab

app/models/crate.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default class Crate extends Model {
1818
* @type {string | null}
1919
*/
2020
@attr default_version;
21+
@attr num_versions;
2122
@attr yanked;
2223
@attr max_version;
2324
@attr max_stable_version;

app/templates/crate/versions.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<div local-class="results-meta">
44
<span local-class="page-description" data-test-page-description>
5-
All <strong>{{ this.model.versions.length }}</strong>
5+
All <strong>{{ this.model.num_versions }}</strong>
66
versions of <strong>{{ this.model.name }}</strong> since
77
{{date-format this.model.created_at 'PPP'}}
88
</span>

packages/crates-io-msw/handlers/crates/get.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ test('returns a crate object for known crates', async function () {
3838
max_stable_version: null,
3939
name: 'rand',
4040
newest_version: '1.0.0-beta.1',
41+
num_versions: 1,
4142
repository: null,
4243
recent_downloads: 321,
4344
updated_at: '2017-02-24T12:34:56Z',
@@ -101,6 +102,7 @@ test('works for non-canonical names', async function () {
101102
max_stable_version: null,
102103
name: 'foo-bar',
103104
newest_version: '1.0.0-beta.1',
105+
num_versions: 1,
104106
repository: null,
105107
recent_downloads: 321,
106108
updated_at: '2017-02-24T12:34:56Z',

packages/crates-io-msw/handlers/crates/list.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ test('returns a paginated crates list', async function () {
5555
max_stable_version: '1.0.0',
5656
name: 'rand',
5757
newest_version: '2.0.0-beta.1',
58+
num_versions: 2,
5859
repository: null,
5960
recent_downloads: 321,
6061
updated_at: '2017-02-24T12:34:56Z',

packages/crates-io-msw/handlers/summary.test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ test('returns the data for the front page', async function () {
5151
max_stable_version: '1.0.0',
5252
name: 'crate-1',
5353
newest_version: '1.0.0',
54+
num_versions: 1,
5455
recent_downloads: 321,
5556
repository: null,
5657
updated_at: '2017-02-24T12:34:56Z',
@@ -81,6 +82,7 @@ test('returns the data for the front page', async function () {
8182
max_stable_version: '1.0.3',
8283
name: 'crate-4',
8384
newest_version: '1.0.3',
85+
num_versions: 1,
8486
repository: null,
8587
recent_downloads: 963,
8688
updated_at: '2017-02-24T12:34:56Z',
@@ -111,6 +113,7 @@ test('returns the data for the front page', async function () {
111113
max_stable_version: '1.0.10',
112114
name: 'crate-11',
113115
newest_version: '1.0.10',
116+
num_versions: 1,
114117
repository: null,
115118
recent_downloads: 3852,
116119
updated_at: '2017-02-24T12:34:56Z',
@@ -141,6 +144,7 @@ test('returns the data for the front page', async function () {
141144
max_stable_version: '1.0.19',
142145
name: 'crate-20',
143146
newest_version: '1.0.19',
147+
num_versions: 1,
144148
repository: null,
145149
recent_downloads: 1605,
146150
updated_at: '2017-02-24T12:34:56Z',

packages/crates-io-msw/serializers/crate.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export function serializeCrate(
2727
versionNums.find(it => !versionsByNum[it].yanked) ??
2828
versionNums[0];
2929

30+
serialized.num_versions = versions.length;
31+
3032
serialized.yanked = versionsByNum[serialized.default_version]?.yanked ?? false;
3133

3234
serialized.links = {

src/controllers/krate/metadata.rs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,27 @@ pub async fn find_crate(
7575
.transpose()?
7676
.unwrap_or_default();
7777

78-
let (krate, downloads, default_version, yanked): (Crate, i64, Option<String>, Option<bool>) =
79-
Crate::by_name(&path.name)
80-
.inner_join(crate_downloads::table)
81-
.left_join(default_versions::table)
82-
.left_join(versions::table.on(default_versions::version_id.eq(versions::id)))
83-
.select((
84-
Crate::as_select(),
85-
crate_downloads::downloads,
86-
versions::num.nullable(),
87-
versions::yanked.nullable(),
88-
))
89-
.first(&mut conn)
90-
.await
91-
.optional()?
92-
.ok_or_else(|| crate_not_found(&path.name))?;
78+
let (krate, downloads, default_version, yanked, num_versions): (
79+
Crate,
80+
i64,
81+
Option<String>,
82+
Option<bool>,
83+
Option<i32>,
84+
) = Crate::by_name(&path.name)
85+
.inner_join(crate_downloads::table)
86+
.left_join(default_versions::table)
87+
.left_join(versions::table.on(default_versions::version_id.eq(versions::id)))
88+
.select((
89+
Crate::as_select(),
90+
crate_downloads::downloads,
91+
versions::num.nullable(),
92+
versions::yanked.nullable(),
93+
default_versions::num_versions.nullable(),
94+
))
95+
.first(&mut conn)
96+
.await
97+
.optional()?
98+
.ok_or_else(|| crate_not_found(&path.name))?;
9399

94100
let mut versions_publishers_and_audit_actions = if include.versions {
95101
let versions_and_publishers: Vec<(Version, Option<User>)> = Version::belonging_to(&krate)
@@ -183,6 +189,7 @@ pub async fn find_crate(
183189
let encodable_crate = EncodableCrate::from(
184190
krate.clone(),
185191
default_version.as_deref(),
192+
num_versions.unwrap_or_default(),
186193
yanked,
187194
top_versions.as_ref(),
188195
ids,

src/controllers/krate/publish.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,12 @@ pub async fn publish(app: AppState, req: Parts, body: Body) -> AppResult<Json<Go
436436
let existing_default_version = default_versions::table
437437
.inner_join(versions::table)
438438
.filter(default_versions::crate_id.eq(krate.id))
439-
.select(DefaultVersion::as_select())
440-
.first(conn)
439+
.select((DefaultVersion::as_select(), default_versions::num_versions))
440+
.first::<(DefaultVersion, Option<i32>)>(conn)
441441
.await
442442
.optional()?;
443443

444+
let num_versions = existing_default_version.as_ref().and_then(|t|t.1).unwrap_or_default();
444445
let mut default_version = None;
445446
// Upsert the `default_value` determined by the existing `default_value` and the
446447
// published version. Note that this could potentially write an outdated version
@@ -450,7 +451,7 @@ pub async fn publish(app: AppState, req: Parts, body: Body) -> AppResult<Json<Go
450451
// Compared to only using a background job, this prevents us from getting into a
451452
// situation where a crate exists in the `crates` table but doesn't have a default
452453
// version in the `default_versions` table.
453-
if let Some(existing_default_version) = existing_default_version {
454+
if let Some((existing_default_version, _)) = existing_default_version {
454455
let published_default_version = DefaultVersion {
455456
id: version.id,
456457
num: semver,
@@ -562,6 +563,7 @@ pub async fn publish(app: AppState, req: Parts, body: Body) -> AppResult<Json<Go
562563
krate: EncodableCrate::from_minimal(
563564
krate,
564565
default_version.or(Some(version_string)).as_deref(),
566+
num_versions,
565567
Some(false),
566568
Some(&top_versions),
567569
false,

src/controllers/krate/search.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub async fn list_crates(
8282
0_f32.into_sql::<Float>(),
8383
versions::num.nullable(),
8484
versions::yanked.nullable(),
85+
default_versions::num_versions.nullable(),
8586
);
8687

8788
let mut seek: Option<Seek> = None;
@@ -113,6 +114,7 @@ pub async fn list_crates(
113114
rank,
114115
versions::num.nullable(),
115116
versions::yanked.nullable(),
117+
default_versions::num_versions.nullable(),
116118
));
117119
seek = Some(Seek::Relevance);
118120
query = query.then_order_by(rank.desc())
@@ -125,6 +127,7 @@ pub async fn list_crates(
125127
0_f32.into_sql::<Float>(),
126128
versions::num.nullable(),
127129
versions::yanked.nullable(),
130+
default_versions::num_versions.nullable(),
128131
));
129132
seek = Some(Seek::Query);
130133
}
@@ -227,6 +230,7 @@ pub async fn list_crates(
227230
EncodableCrate::from_minimal(
228231
record.krate,
229232
record.default_version.as_deref(),
233+
record.num_versions.unwrap_or_default(),
230234
record.yanked,
231235
Some(&max_version),
232236
record.exact_match,
@@ -704,6 +708,7 @@ struct Record {
704708
rank: f32,
705709
default_version: Option<String>,
706710
yanked: Option<bool>,
711+
num_versions: Option<i32>,
707712
}
708713

709714
type QuerySource = LeftJoinQuerySource<

0 commit comments

Comments
 (0)