Skip to content

Commit 77d5cae

Browse files
authored
Merge pull request #831 from Turbo87/mirage
mirage: Convert "fixtures" to actual mirage fixtures
2 parents f94a74d + a464fbb commit 77d5cae

33 files changed

+1230
-1189
lines changed

mirage/config.js

Lines changed: 213 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,235 @@
1-
import summaryFixture from '../mirage/fixtures/summary';
2-
import searchFixture from '../mirage/fixtures/search';
3-
import categoriesFixture from '../mirage/fixtures/categories';
4-
import crateFixture from '../mirage/fixtures/crate';
5-
import crateVersionsFixture from '../mirage/fixtures/crate_versions';
6-
import crateAuthorsFixture from '../mirage/fixtures/crate_authors';
7-
import crateOwnersFixture from '../mirage/fixtures/crate_owners';
8-
import crateTeamsFixture from '../mirage/fixtures/crate_teams';
9-
import crateReverseDependenciesFixture from '../mirage/fixtures/crate_reverse_dependencies';
10-
import crateDependenciesFixture from '../mirage/fixtures/crate_dependencies';
11-
import crateDownloadsFixture from '../mirage/fixtures/crate_downloads';
12-
import keywordFixture from '../mirage/fixtures/keyword';
13-
import teamFixture from '../mirage/fixtures/team';
14-
import userFixture from '../mirage/fixtures/user';
1+
import Response from 'ember-cli-mirage/response';
152

163
export default function() {
17-
this.get('/summary', () => summaryFixture);
4+
this.get('/summary', function(schema) {
5+
let crates = schema.crates.all();
186

19-
this.get('/api/v1/crates', (db, request) => {
20-
const { start, end } = pageParams(request);
21-
const payload = {
22-
crates: searchFixture.crates.slice(start, end),
23-
meta: searchFixture.meta,
7+
let just_updated = crates.sort((a, b) => compareIsoDates(b.updated_at, a.updated_at)).slice(0, 10);
8+
let most_downloaded = crates.sort((a, b) => b.downloads - a.downloads).slice(0, 10);
9+
let new_crates = crates.sort((a, b) => compareIsoDates(b.created_at, a.created_at)).slice(0, 10);
10+
11+
let num_crates = crates.length;
12+
let num_downloads = crates.models.reduce((sum, crate) => sum + crate.downloads, 0);
13+
14+
let popular_categories = schema.categories.all().sort((a, b) => b.crates_cnt - a.crates_cnt).slice(0, 10);
15+
let popular_keywords = schema.keywords.all().sort((a, b) => b.crates_cnt - a.crates_cnt).slice(0, 10);
16+
17+
return {
18+
just_updated: this.serialize(just_updated).crates
19+
.map(it => ({ ...it, versions: null })),
20+
most_downloaded: this.serialize(most_downloaded).crates
21+
.map(it => ({ ...it, versions: null })),
22+
new_crates: this.serialize(new_crates).crates
23+
.map(it => ({ ...it, versions: null })),
24+
num_crates,
25+
num_downloads,
26+
popular_categories: this.serialize(popular_categories).categories,
27+
popular_keywords: this.serialize(popular_keywords).keywords,
2428
};
29+
});
30+
31+
this.namespace = '/api/v1';
32+
33+
this.get('/crates', function(schema, request) {
34+
const { start, end } = pageParams(request);
35+
36+
let crates = schema.crates.all();
37+
38+
if (request.queryParams.letter) {
39+
let letter = request.queryParams.letter.toLowerCase();
40+
crates = crates.filter(crate => crate.id[0].toLowerCase() === letter);
41+
}
42+
43+
if (request.queryParams.q) {
44+
let q = request.queryParams.q.toLowerCase();
45+
crates = crates.filter(crate => crate.id.toLowerCase().indexOf(q) !== -1);
46+
}
47+
48+
if (request.queryParams.user_id) {
49+
let userId = parseInt(request.queryParams.user_id, 10);
50+
crates = crates.filter(crate => (crate._owner_users || []).indexOf(userId) !== -1);
51+
}
2552

2653
if (request.queryParams.team_id) {
27-
payload.team = teamFixture.team;
28-
} else if (request.queryParams.user_id) {
29-
payload.user = userFixture.user;
54+
let teamId = parseInt(request.queryParams.team_id, 10);
55+
crates = crates.filter(crate => (crate._owner_teams || []).indexOf(teamId) !== -1);
56+
}
57+
58+
if (request.queryParams.sort === 'alpha') {
59+
crates = crates.sort((a, b) => compareStrings(a.id.toLowerCase(), b.id.toLowerCase()));
3060
}
3161

32-
return payload;
62+
return withMeta(this.serialize(crates.slice(start, end)), { total: crates.length });
3363
});
3464

35-
this.get('/api/v1/categories', () => categoriesFixture);
65+
this.get('/crates/:crate_id', function(schema, request) {
66+
let crateId = request.params.crate_id;
67+
let crate = schema.crates.find(crateId);
68+
let categories = schema.categories.all()
69+
.filter(category => (crate.categories || []).indexOf(category.id) !== -1);
70+
let keywords = schema.keywords.all()
71+
.filter(keyword => (crate.keywords || []).indexOf(keyword.id) !== -1);
72+
let versions = schema.versions.all()
73+
.filter(version => (crate.versions || []).indexOf(parseInt(version.id, 10)) !== -1);
74+
75+
return {
76+
...this.serialize(crate),
77+
...this.serialize(categories),
78+
...this.serialize(keywords),
79+
...this.serialize(versions),
80+
};
81+
});
82+
83+
this.get('/crates/:crate_id/versions', (schema, request) => {
84+
let crate = request.params.crate_id;
85+
return schema.versions.where({ crate }).sort((a, b) => compareIsoDates(b.created_at, a.created_at));
86+
});
87+
88+
this.get('/crates/:crate_id/:version_num/authors', (schema, request) => {
89+
let crate = request.params.crate_id;
90+
let num = request.params.version_num;
91+
let version = schema.versions.findBy({ crate, num });
92+
return { meta: { names: version._authors }, users: [] };
93+
});
94+
95+
this.get('/crates/:crate_id/:version_num/dependencies', (schema, request) => {
96+
let crate = request.params.crate_id;
97+
let num = request.params.version_num;
98+
let version_id = schema.versions.findBy({ crate, num }).id;
99+
return schema.dependencies.where({ version_id });
100+
});
101+
102+
this.get('/crates/:crate_id/:version_num/downloads', function(schema, request) {
103+
let crateId = request.params.crate_id;
104+
let versionNum = request.params.version_num;
105+
let versionId = schema.versions.findBy({ crate: crateId, num: versionNum }).id;
106+
return schema.versionDownloads.where({ version: versionId });
107+
});
108+
109+
this.get('/crates/:crate_id/owner_user', function(schema, request) {
110+
let crateId = request.params.crate_id;
111+
let crate = schema.crates.find(crateId);
112+
let users = schema.users.find(crate._owner_users);
113+
114+
let response = this.serialize(users);
115+
116+
response.users.forEach(user => {
117+
user.kind = 'user';
118+
});
119+
120+
return response;
121+
});
122+
123+
this.get('/crates/:crate_id/owner_team', function(schema, request) {
124+
let crateId = request.params.crate_id;
125+
let crate = schema.crates.find(crateId);
126+
let teams = schema.teams.find(crate._owner_teams);
127+
128+
let response = this.serialize(teams);
36129

37-
this.get('/api/v1/crates/nanomsg', () => crateFixture);
38-
this.get('/api/v1/crates/nanomsg/versions', () => crateVersionsFixture);
39-
this.get('/api/v1/crates/nanomsg/:version_num/authors', () => crateAuthorsFixture);
40-
this.get('/api/v1/crates/nanomsg/owner_user', () => crateOwnersFixture);
41-
this.get('/api/v1/crates/nanomsg/owner_team', () => crateTeamsFixture);
42-
this.get('/api/v1/crates/nanomsg/reverse_dependencies', () => crateReverseDependenciesFixture);
43-
this.get('/api/v1/crates/nanomsg/:version_num/dependencies', () => crateDependenciesFixture);
44-
this.get('/api/v1/crates/nanomsg/downloads', () => crateDownloadsFixture);
45-
this.get('/api/v1/crates/nanomsg/:version_num/downloads', () => crateDownloadsFixture);
46-
this.get('/api/v1/keywords/network', () => keywordFixture);
47-
this.get('/api/v1/teams/:team_id', () => teamFixture);
48-
this.get('/api/v1/users/:user_id', () => userFixture);
130+
response.teams.forEach(team => {
131+
team.kind = 'team';
132+
});
133+
134+
return response;
135+
});
136+
137+
this.get('/crates/:crate_id/reverse_dependencies', function(schema, request) {
138+
let { start, end } = pageParams(request);
139+
140+
let crate = request.params.crate_id;
141+
let allDependencies = schema.dependencies.where({ crate_id: crate });
142+
let dependencies = allDependencies.slice(start, end);
143+
let total = allDependencies.length;
144+
145+
let serialized = this.serialize(dependencies);
146+
147+
// TODO https://github.com/rust-lang/crates.io/pull/810
148+
serialized.dependencies.forEach(dep => {
149+
let version = schema.versions.find(dep.version_id);
150+
dep.crate_id = version.crate;
151+
});
152+
153+
return withMeta(serialized, { total });
154+
});
155+
156+
this.get('/crates/:crate_id/downloads', function(schema, request) {
157+
let crateId = request.params.crate_id;
158+
let crate = schema.crates.find(crateId);
159+
let versionDownloads = schema.versionDownloads.all()
160+
.filter(it => crate.versions.indexOf(parseInt(it.version, 10)) !== -1);
161+
162+
return withMeta(this.serialize(versionDownloads), { extra_downloads: crate._extra_downloads });
163+
});
164+
165+
this.get('/categories', function(schema, request) {
166+
let { start, end } = pageParams(request);
167+
168+
let allCategories = schema.categories.all().sort((a, b) => compareStrings(a.category, b.category));
169+
let categories = allCategories.slice(start, end);
170+
let total = allCategories.length;
171+
172+
return withMeta(this.serialize(categories), { total });
173+
});
174+
175+
this.get('/keywords', function(schema, request) {
176+
let { start, end } = pageParams(request);
177+
178+
let allKeywords = schema.keywords.all().sort((a, b) => a.crates_cnt - b.crates_cnt);
179+
let keywords = allKeywords.slice(start, end);
180+
let total = allKeywords.length;
181+
182+
return withMeta(this.serialize(keywords), { total });
183+
});
184+
185+
this.get('/keywords/:keyword_id', (schema, request) => {
186+
let keywordId = request.params.keyword_id;
187+
let keyword = schema.keywords.find(keywordId);
188+
return keyword ? keyword : notFound();
189+
});
190+
191+
this.get('/teams/:team_id', (schema, request) => {
192+
let login = request.params.team_id;
193+
let team = schema.teams.findBy({ login });
194+
return team ? team : notFound();
195+
});
196+
197+
this.get('/users/:user_id', (schema, request) => {
198+
let login = request.params.user_id;
199+
let user = schema.users.findBy({ login });
200+
return user ? user : notFound();
201+
});
202+
}
203+
204+
function notFound() {
205+
return new Response(404, { 'Content-Type': 'application/json' }, {
206+
'errors': [{ 'detail': 'Not Found' }]
207+
});
49208
}
50209

51210
function pageParams(request) {
52211
const { queryParams } = request;
53212

54-
const page = parseInt(queryParams.page);
55-
const perPage = parseInt(queryParams.per_page);
213+
const page = parseInt(queryParams.page || '1');
214+
const perPage = parseInt(queryParams.per_page || '10');
56215

57216
const start = (page - 1) * perPage;
58217
const end = start + perPage;
59218

60219
return { page, perPage, start, end };
61220
}
221+
222+
function withMeta(response, meta) {
223+
response.meta = meta;
224+
return response;
225+
}
226+
227+
function compareStrings(a, b) {
228+
return (a < b) ? -1 : (a > b) ? 1 : 0;
229+
}
230+
231+
function compareIsoDates(a, b) {
232+
let aDate = new Date(a);
233+
let bDate = new Date(b);
234+
return (aDate < bDate) ? -1 : (aDate > bDate) ? 1 : 0;
235+
}

mirage/fixtures/categories.js

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,23 @@
11
/* eslint-disable quotes */
2-
export default {
3-
"categories": [{
4-
"category": "API bindings",
5-
"crates_cnt": 0,
6-
"created_at": "2017-01-20T14:51:49Z",
7-
"description": "Idiomatic wrappers of specific APIs for convenient access from Rust. Includes HTTP API wrappers as well. Non-idiomatic or unsafe bindings can be found in External FFI bindings.",
8-
"id": "api-bindings",
9-
"slug": "api-bindings"
10-
}, {
11-
"category": "Algorithms",
12-
"crates_cnt": 1,
13-
"created_at": "2017-01-20T14:51:49Z",
14-
"description": "Rust implementations of core algorithms such as hashing, sorting, searching, and more.",
15-
"id": "algorithms",
16-
"slug": "algorithms"
17-
}, {
18-
"category": "Asynchronous",
19-
"crates_cnt": 3910,
20-
"created_at": "2017-01-20T14:51:49Z",
21-
"description": "Crates to help you deal with events independently of the main program flow, using techniques like futures, promises, waiting, or eventing.",
22-
"id": "asynchronous",
23-
"slug": "asynchronous"
24-
}],
25-
"meta": {
26-
"total": 3
27-
}
28-
};
2+
export default [{
3+
"category": "API bindings",
4+
"crates_cnt": 0,
5+
"created_at": "2017-01-20T14:51:49Z",
6+
"description": "Idiomatic wrappers of specific APIs for convenient access from Rust. Includes HTTP API wrappers as well. Non-idiomatic or unsafe bindings can be found in External FFI bindings.",
7+
"id": "api-bindings",
8+
"slug": "api-bindings"
9+
}, {
10+
"category": "Algorithms",
11+
"crates_cnt": 1,
12+
"created_at": "2017-01-20T14:51:49Z",
13+
"description": "Rust implementations of core algorithms such as hashing, sorting, searching, and more.",
14+
"id": "algorithms",
15+
"slug": "algorithms"
16+
}, {
17+
"category": "Asynchronous",
18+
"crates_cnt": 3910,
19+
"created_at": "2017-01-20T14:51:49Z",
20+
"description": "Crates to help you deal with events independently of the main program flow, using techniques like futures, promises, waiting, or eventing.",
21+
"id": "asynchronous",
22+
"slug": "asynchronous"
23+
}];

0 commit comments

Comments
 (0)