Skip to content

mirage: Convert "fixtures" to actual mirage fixtures #831

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jun 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c5a7ec1
mirage/serializers/application: Use "Serializer" as base class
Turbo87 Jun 28, 2017
a367c06
mirage/config: Set "namespace" property to avoid repetition
Turbo87 Jun 28, 2017
7a7adc2
mirage/config: Add notFound() helper function
Turbo87 Jun 28, 2017
7ac3153
mirage: Convert "user" fixture to a real mirage fixture
Turbo87 Jun 28, 2017
2838efc
mirage: Convert "team" fixture to a real mirage fixture
Turbo87 Jun 28, 2017
7c97081
mirage: Convert "keywords" fixture to a real mirage fixture
Turbo87 Jun 28, 2017
26f5a71
mirage/config: Implement "GET /keywords" handler
Turbo87 Jun 28, 2017
8146baf
mirage/config: Replace hardcoded "nanomsg" crate name with ":crate_id…
Turbo87 Jun 28, 2017
1507f4c
mirage: Convert "versions" fixture to a real mirage fixture
Turbo87 Jun 28, 2017
9b95798
mirage/config: Implement "GET /crates/:crate_id/:version_num/authors"…
Turbo87 Jun 28, 2017
f905ba4
mirage: Convert "categories" fixture to a real mirage fixture
Turbo87 Jun 28, 2017
0052c63
mirage: Convert "dependencies" fixture to a real mirage fixture
Turbo87 Jun 28, 2017
727f8b9
mirage/config: Implement "GET /crates/:crate_id/reverse_dependencies"…
Turbo87 Jun 28, 2017
d5651c6
mirage: Convert "crate" fixture to a real mirage fixture
Turbo87 Jun 28, 2017
fa4380d
mirage: Convert "crate_downloads" fixture to a real mirage fixture
Turbo87 Jun 28, 2017
6a4afcd
mirage/config: Implement "GET /crates/:crate_id/owner_team" handler
Turbo87 Jun 28, 2017
205daa2
mirage/config: Implement "GET /crates/:crate_id/owner_user" handler
Turbo87 Jun 28, 2017
4dd83a6
mirage/config: Implement "GET /crates" handler
Turbo87 Jun 28, 2017
89a7113
mirage/config: Implement "GET /summary" handler
Turbo87 Jun 29, 2017
a464fbb
mirage/config: Adjust "GET /crates/:crate_id/versions" sort order
Turbo87 Jun 29, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
252 changes: 213 additions & 39 deletions mirage/config.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,235 @@
import summaryFixture from '../mirage/fixtures/summary';
import searchFixture from '../mirage/fixtures/search';
import categoriesFixture from '../mirage/fixtures/categories';
import crateFixture from '../mirage/fixtures/crate';
import crateVersionsFixture from '../mirage/fixtures/crate_versions';
import crateAuthorsFixture from '../mirage/fixtures/crate_authors';
import crateOwnersFixture from '../mirage/fixtures/crate_owners';
import crateTeamsFixture from '../mirage/fixtures/crate_teams';
import crateReverseDependenciesFixture from '../mirage/fixtures/crate_reverse_dependencies';
import crateDependenciesFixture from '../mirage/fixtures/crate_dependencies';
import crateDownloadsFixture from '../mirage/fixtures/crate_downloads';
import keywordFixture from '../mirage/fixtures/keyword';
import teamFixture from '../mirage/fixtures/team';
import userFixture from '../mirage/fixtures/user';
import Response from 'ember-cli-mirage/response';

export default function() {
this.get('/summary', () => summaryFixture);
this.get('/summary', function(schema) {
let crates = schema.crates.all();

this.get('/api/v1/crates', (db, request) => {
const { start, end } = pageParams(request);
const payload = {
crates: searchFixture.crates.slice(start, end),
meta: searchFixture.meta,
let just_updated = crates.sort((a, b) => compareIsoDates(b.updated_at, a.updated_at)).slice(0, 10);
let most_downloaded = crates.sort((a, b) => b.downloads - a.downloads).slice(0, 10);
let new_crates = crates.sort((a, b) => compareIsoDates(b.created_at, a.created_at)).slice(0, 10);

let num_crates = crates.length;
let num_downloads = crates.models.reduce((sum, crate) => sum + crate.downloads, 0);

let popular_categories = schema.categories.all().sort((a, b) => b.crates_cnt - a.crates_cnt).slice(0, 10);
let popular_keywords = schema.keywords.all().sort((a, b) => b.crates_cnt - a.crates_cnt).slice(0, 10);

return {
just_updated: this.serialize(just_updated).crates
.map(it => ({ ...it, versions: null })),
most_downloaded: this.serialize(most_downloaded).crates
.map(it => ({ ...it, versions: null })),
new_crates: this.serialize(new_crates).crates
.map(it => ({ ...it, versions: null })),
num_crates,
num_downloads,
popular_categories: this.serialize(popular_categories).categories,
popular_keywords: this.serialize(popular_keywords).keywords,
};
});

this.namespace = '/api/v1';

this.get('/crates', function(schema, request) {
const { start, end } = pageParams(request);

let crates = schema.crates.all();

if (request.queryParams.letter) {
let letter = request.queryParams.letter.toLowerCase();
crates = crates.filter(crate => crate.id[0].toLowerCase() === letter);
}

if (request.queryParams.q) {
let q = request.queryParams.q.toLowerCase();
crates = crates.filter(crate => crate.id.toLowerCase().indexOf(q) !== -1);
}

if (request.queryParams.user_id) {
let userId = parseInt(request.queryParams.user_id, 10);
crates = crates.filter(crate => (crate._owner_users || []).indexOf(userId) !== -1);
}

if (request.queryParams.team_id) {
payload.team = teamFixture.team;
} else if (request.queryParams.user_id) {
payload.user = userFixture.user;
let teamId = parseInt(request.queryParams.team_id, 10);
crates = crates.filter(crate => (crate._owner_teams || []).indexOf(teamId) !== -1);
}

if (request.queryParams.sort === 'alpha') {
crates = crates.sort((a, b) => compareStrings(a.id.toLowerCase(), b.id.toLowerCase()));
}

return payload;
return withMeta(this.serialize(crates.slice(start, end)), { total: crates.length });
});

this.get('/api/v1/categories', () => categoriesFixture);
this.get('/crates/:crate_id', function(schema, request) {
let crateId = request.params.crate_id;
let crate = schema.crates.find(crateId);
let categories = schema.categories.all()
.filter(category => (crate.categories || []).indexOf(category.id) !== -1);
let keywords = schema.keywords.all()
.filter(keyword => (crate.keywords || []).indexOf(keyword.id) !== -1);
let versions = schema.versions.all()
.filter(version => (crate.versions || []).indexOf(parseInt(version.id, 10)) !== -1);

return {
...this.serialize(crate),
...this.serialize(categories),
...this.serialize(keywords),
...this.serialize(versions),
};
});

this.get('/crates/:crate_id/versions', (schema, request) => {
let crate = request.params.crate_id;
return schema.versions.where({ crate }).sort((a, b) => compareIsoDates(b.created_at, a.created_at));
});

this.get('/crates/:crate_id/:version_num/authors', (schema, request) => {
let crate = request.params.crate_id;
let num = request.params.version_num;
let version = schema.versions.findBy({ crate, num });
return { meta: { names: version._authors }, users: [] };
});

this.get('/crates/:crate_id/:version_num/dependencies', (schema, request) => {
let crate = request.params.crate_id;
let num = request.params.version_num;
let version_id = schema.versions.findBy({ crate, num }).id;
return schema.dependencies.where({ version_id });
});

this.get('/crates/:crate_id/:version_num/downloads', function(schema, request) {
let crateId = request.params.crate_id;
let versionNum = request.params.version_num;
let versionId = schema.versions.findBy({ crate: crateId, num: versionNum }).id;
return schema.versionDownloads.where({ version: versionId });
});

this.get('/crates/:crate_id/owner_user', function(schema, request) {
let crateId = request.params.crate_id;
let crate = schema.crates.find(crateId);
let users = schema.users.find(crate._owner_users);

let response = this.serialize(users);

response.users.forEach(user => {
user.kind = 'user';
});

return response;
});

this.get('/crates/:crate_id/owner_team', function(schema, request) {
let crateId = request.params.crate_id;
let crate = schema.crates.find(crateId);
let teams = schema.teams.find(crate._owner_teams);

let response = this.serialize(teams);

this.get('/api/v1/crates/nanomsg', () => crateFixture);
this.get('/api/v1/crates/nanomsg/versions', () => crateVersionsFixture);
this.get('/api/v1/crates/nanomsg/:version_num/authors', () => crateAuthorsFixture);
this.get('/api/v1/crates/nanomsg/owner_user', () => crateOwnersFixture);
this.get('/api/v1/crates/nanomsg/owner_team', () => crateTeamsFixture);
this.get('/api/v1/crates/nanomsg/reverse_dependencies', () => crateReverseDependenciesFixture);
this.get('/api/v1/crates/nanomsg/:version_num/dependencies', () => crateDependenciesFixture);
this.get('/api/v1/crates/nanomsg/downloads', () => crateDownloadsFixture);
this.get('/api/v1/crates/nanomsg/:version_num/downloads', () => crateDownloadsFixture);
this.get('/api/v1/keywords/network', () => keywordFixture);
this.get('/api/v1/teams/:team_id', () => teamFixture);
this.get('/api/v1/users/:user_id', () => userFixture);
response.teams.forEach(team => {
team.kind = 'team';
});

return response;
});

this.get('/crates/:crate_id/reverse_dependencies', function(schema, request) {
let { start, end } = pageParams(request);

let crate = request.params.crate_id;
let allDependencies = schema.dependencies.where({ crate_id: crate });
let dependencies = allDependencies.slice(start, end);
let total = allDependencies.length;

let serialized = this.serialize(dependencies);

// TODO https://github.com/rust-lang/crates.io/pull/810
serialized.dependencies.forEach(dep => {
let version = schema.versions.find(dep.version_id);
dep.crate_id = version.crate;
});

return withMeta(serialized, { total });
});

this.get('/crates/:crate_id/downloads', function(schema, request) {
let crateId = request.params.crate_id;
let crate = schema.crates.find(crateId);
let versionDownloads = schema.versionDownloads.all()
.filter(it => crate.versions.indexOf(parseInt(it.version, 10)) !== -1);

return withMeta(this.serialize(versionDownloads), { extra_downloads: crate._extra_downloads });
});

this.get('/categories', function(schema, request) {
let { start, end } = pageParams(request);

let allCategories = schema.categories.all().sort((a, b) => compareStrings(a.category, b.category));
let categories = allCategories.slice(start, end);
let total = allCategories.length;

return withMeta(this.serialize(categories), { total });
});

this.get('/keywords', function(schema, request) {
let { start, end } = pageParams(request);

let allKeywords = schema.keywords.all().sort((a, b) => a.crates_cnt - b.crates_cnt);
let keywords = allKeywords.slice(start, end);
let total = allKeywords.length;

return withMeta(this.serialize(keywords), { total });
});

this.get('/keywords/:keyword_id', (schema, request) => {
let keywordId = request.params.keyword_id;
let keyword = schema.keywords.find(keywordId);
return keyword ? keyword : notFound();
});

this.get('/teams/:team_id', (schema, request) => {
let login = request.params.team_id;
let team = schema.teams.findBy({ login });
return team ? team : notFound();
});

this.get('/users/:user_id', (schema, request) => {
let login = request.params.user_id;
let user = schema.users.findBy({ login });
return user ? user : notFound();
});
}

function notFound() {
return new Response(404, { 'Content-Type': 'application/json' }, {
'errors': [{ 'detail': 'Not Found' }]
});
}

function pageParams(request) {
const { queryParams } = request;

const page = parseInt(queryParams.page);
const perPage = parseInt(queryParams.per_page);
const page = parseInt(queryParams.page || '1');
const perPage = parseInt(queryParams.per_page || '10');

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

return { page, perPage, start, end };
}

function withMeta(response, meta) {
response.meta = meta;
return response;
}

function compareStrings(a, b) {
return (a < b) ? -1 : (a > b) ? 1 : 0;
}

function compareIsoDates(a, b) {
let aDate = new Date(a);
let bDate = new Date(b);
return (aDate < bDate) ? -1 : (aDate > bDate) ? 1 : 0;
}
49 changes: 22 additions & 27 deletions mirage/fixtures/categories.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
/* eslint-disable quotes */
export default {
"categories": [{
"category": "API bindings",
"crates_cnt": 0,
"created_at": "2017-01-20T14:51:49Z",
"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.",
"id": "api-bindings",
"slug": "api-bindings"
}, {
"category": "Algorithms",
"crates_cnt": 1,
"created_at": "2017-01-20T14:51:49Z",
"description": "Rust implementations of core algorithms such as hashing, sorting, searching, and more.",
"id": "algorithms",
"slug": "algorithms"
}, {
"category": "Asynchronous",
"crates_cnt": 3910,
"created_at": "2017-01-20T14:51:49Z",
"description": "Crates to help you deal with events independently of the main program flow, using techniques like futures, promises, waiting, or eventing.",
"id": "asynchronous",
"slug": "asynchronous"
}],
"meta": {
"total": 3
}
};
export default [{
"category": "API bindings",
"crates_cnt": 0,
"created_at": "2017-01-20T14:51:49Z",
"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.",
"id": "api-bindings",
"slug": "api-bindings"
}, {
"category": "Algorithms",
"crates_cnt": 1,
"created_at": "2017-01-20T14:51:49Z",
"description": "Rust implementations of core algorithms such as hashing, sorting, searching, and more.",
"id": "algorithms",
"slug": "algorithms"
}, {
"category": "Asynchronous",
"crates_cnt": 3910,
"created_at": "2017-01-20T14:51:49Z",
"description": "Crates to help you deal with events independently of the main program flow, using techniques like futures, promises, waiting, or eventing.",
"id": "asynchronous",
"slug": "asynchronous"
}];
Loading