From 899eeb1b5fea8137352811883d7adc32ea607293 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Mon, 30 Dec 2024 18:40:48 +0800 Subject: [PATCH] mirage: Respect `include` query params in `GET /api/v1/crates/:id` (#10276) --- mirage/route-handlers/crates.js | 13 +++++--- mirage/serializers/crate.js | 44 ++++++++++++++++++--------- tests/mirage/crates/get-by-id-test.js | 30 ++++++++++++++++++ 3 files changed, 68 insertions(+), 19 deletions(-) diff --git a/mirage/route-handlers/crates.js b/mirage/route-handlers/crates.js index 0e84d26eadc..637dbf7430a 100644 --- a/mirage/route-handlers/crates.js +++ b/mirage/route-handlers/crates.js @@ -58,12 +58,15 @@ export function register(server) { let { name } = request.params; let crate = schema.crates.findBy({ name }); if (!crate) return notFound(); - + let serialized = this.serialize(crate); return { - ...this.serialize(crate), - ...this.serialize(crate.categories), - ...this.serialize(crate.keywords), - ...this.serialize(crate.versions.sort((a, b) => Number(b.id) - Number(a.id))), + categories: null, + keywords: null, + versions: null, + ...serialized, + ...(serialized.crate.categories && this.serialize(crate.categories)), + ...(serialized.crate.keywords && this.serialize(crate.keywords)), + ...(serialized.crate.versions && this.serialize(crate.versions.sort((a, b) => Number(b.id) - Number(a.id)))), }; }); diff --git a/mirage/serializers/crate.js b/mirage/serializers/crate.js index 12a38b32918..bb9ee87f125 100644 --- a/mirage/serializers/crate.js +++ b/mirage/serializers/crate.js @@ -6,7 +6,15 @@ import semverSort from 'semver/functions/rsort'; import { compareIsoDates } from '../route-handlers/-utils'; import BaseSerializer from './application'; +const VALID_INCLUDE_MODEL = new Set(['versions', 'keywords', 'categories' /*, 'badges', 'downloads' */]); + export default BaseSerializer.extend({ + include(request) { + let include = request.queryParams.include; + return include == null || include === 'full' + ? VALID_INCLUDE_MODEL.values() + : include.split(',').filter(it => VALID_INCLUDE_MODEL.has(it)); + }, attrs: [ 'badges', 'categories', @@ -38,19 +46,20 @@ export default BaseSerializer.extend({ getHashForResource() { let [hash, addToIncludes] = BaseSerializer.prototype.getHashForResource.apply(this, arguments); + let includes = [...this.include(this.request)]; if (Array.isArray(hash)) { for (let resource of hash) { - this._adjust(resource); + this._adjust(resource, includes); } } else { - this._adjust(hash); + this._adjust(hash, includes); } return [hash, addToIncludes]; }, - _adjust(hash) { + _adjust(hash, includes) { let versions = this.schema.versions.where({ crateId: hash.id }); assert(`crate \`${hash.name}\` has no associated versions`, versions.length !== 0); @@ -63,25 +72,32 @@ export default BaseSerializer.extend({ versionNums[0]; hash.yanked = versionsByNum[hash.default_version]?.yanked ?? false; - versions = versions.filter(it => !it.yanked); - versionNums = versionNums.filter(it => !versionsByNum[it].yanked); - hash.max_version = versionNums[0] ?? '0.0.0'; - hash.max_stable_version = versionNums.find(it => !prerelease(it, { loose: true })) ?? null; + if (includes.includes('versions')) { + versions = versions.filter(it => !it.yanked); + versionNums = versionNums.filter(it => !versionsByNum[it].yanked); + hash.max_version = versionNums[0] ?? '0.0.0'; + hash.max_stable_version = versionNums.find(it => !prerelease(it, { loose: true })) ?? null; - let newestVersions = versions.models.sort((a, b) => compareIsoDates(b.updated_at, a.updated_at)); - hash.newest_version = newestVersions[0]?.num ?? '0.0.0'; + let newestVersions = versions.models.sort((a, b) => compareIsoDates(b.updated_at, a.updated_at)); + hash.newest_version = newestVersions[0]?.num ?? '0.0.0'; + + hash.versions = hash.version_ids; + } else { + hash.max_version = '0.0.0'; + hash.newest_version = '0.0.0'; + hash.max_stable_version = null; + hash.versions = null; + } + delete hash.version_ids; hash.id = hash.name; - hash.categories = hash.category_ids; + hash.categories = includes.includes('categories') ? hash.category_ids : null; delete hash.category_ids; - hash.keywords = hash.keyword_ids; + hash.keywords = includes.includes('keywords') ? hash.keyword_ids : null; delete hash.keyword_ids; - hash.versions = hash.version_ids; - delete hash.version_ids; - delete hash.team_owner_ids; delete hash.user_owner_ids; }, diff --git a/tests/mirage/crates/get-by-id-test.js b/tests/mirage/crates/get-by-id-test.js index d43075b07ff..461078b9e4d 100644 --- a/tests/mirage/crates/get-by-id-test.js +++ b/tests/mirage/crates/get-by-id-test.js @@ -193,4 +193,34 @@ module('Mirage | GET /api/v1/crates/:id', function (hooks) { }, ]); }); + + test('without versions included', async function (assert) { + this.server.create('category', { category: 'no-std' }); + this.server.create('category', { category: 'cli' }); + this.server.create('keyword', { keyword: 'no-std' }); + this.server.create('keyword', { keyword: 'cli' }); + let crate = this.server.create('crate', { name: 'rand', categoryIds: ['no-std'], keywordIds: ['no-std'] }); + this.server.create('version', { crate, num: '1.0.0' }); + this.server.create('version', { crate, num: '1.1.0' }); + this.server.create('version', { crate, num: '1.2.0' }); + + let req = await fetch('/api/v1/crates/rand'); + let expected = await req.json(); + + let response = await fetch('/api/v1/crates/rand?include=keywords,categories'); + assert.strictEqual(response.status, 200); + + let responsePayload = await response.json(); + assert.deepEqual(responsePayload, { + ...expected, + crate: { + ...expected.crate, + max_version: '0.0.0', + newest_version: '0.0.0', + max_stable_version: null, + versions: null, + }, + versions: null, + }); + }); });