"use strict";
const dbConnection = require('../lib/db-connection.js');
module.exports = function database(options) {
// input: [{ title: title, description: description, link: link, categories: categories, pubDate: pubDate, date: date }, ...]
// output: { successfull: true/false}
this.add('role:database,news:add', addNews);
// input: { playerId: playerId }
// output: { id: id, link: link, headline: headline, newstext: newstext, newsdate: newsdate, pid: pid }
this.add('role:database,news:get', getNews);
this.add('role:database,players:get', getPlayers);
// input: nothing
// output: [ { } ]
this.add('role:database,clubs:get', getClubs);
this.add('role:database,playerValues:get', getPlayerValues);
this.add('role:database,playerValues:add', addPlayerValues)
this.add('role:database,player:lookUpPlayerId', lookUpPlayerId);
// input: nothing
// output: [ { id, pid, complayerid, name, position, clubid, value, valedate }, ... ]
this.add('role:database,playerValues:getAll', getAllPlayerValues);
this.add('role:database,playerStats:get', getPlayerStats);
this.add('role:database,playerStats:add', addPlayerStats);
this.add('role:database,playerStats:addAll', addAllPlayerStats);
this.add('role:database,game:add', addGame);
this.add('role:database,games:get', getGames);
}
function addNews (msg, respond) {
//validation
if (!msg.data) {
return respond(new Error('data property is not defined as a parameter'));
}
const news = msg.data;
if (Object.prototype.toString.call(news) !== '[object Array]') {
return respond(new Error('data parameter should be an array of news'));
}
dbConnection.addNews(news)
.then(status => respond(null, status))
.catch(err => respond(err));
}
function getNews(msg, respond) {
//validation
if (!msg.data) {
return respond(new Error('data property is not defined as a parameter'));
}
const playerId = msg.data;
if (!playerId)
return respond(new Error('Please specify the playerId property in the data property of the message'));
// defer to dbConnection
dbConnection.getNews(playerId)
.then(news => respond(null, news))
.catch(err => respond(err));
}
function getPlayers (msg, respond) {
dbConnection.getPlayers()
.then(players => respond(null, players))
.catch(err => respond(err));
}
function getClubs (msg, respond) {
dbConnection.getClubs()
.then(clubs => respond(null, clubs))
.catch(err => respond(err));
}
function getPlayerValues (msg, respond) {
if(!msg.data)
return respond(new Error('data property must be defined and it should contain the playerId'));
var playerId = msg.data.playerId;
if (!playerId)
return respond(new Error('Please specify the playerId property in the data property of the message'));
var noOfDays = msg.data.noOfDays;
if (!noOfDays)
return respond(new Error('Please specify the noOfDays property in the data property of the message'));
dbConnection.getPlayerValues(playerId, noOfDays)
.then(playerValues => respond(null, playerValues))
.catch(err => respond(err));
}
function getAllPlayerValues (msg, respond) {
dbConnection.getAllPlayerValues()
.then(playerValues => respond(null, playerValues))
.catch(err => respond(err));
}
/**
* Api function to add player values
* @param {Object} msg.data
* @param {number} msg.data.playerId
* @param {Array.<Object>} msg.data.values
* @param respond
* @returns {*}
*/
function addPlayerValues (msg, respond) {
const dbPromises = [];
if(!msg.data)
return respond(new Error('data property must be defined and it should contain the playerId and a values array containing {date: date, value: value} objects'));
const playerId = msg.data.playerId;
if (!playerId)
return respond(new Error('Please specify the playerId property in the data property of the message'));
const values = msg.data.values;
if (!values) {
return respond(new Error('The value property of data should be an array containing {quote: Integer, valdate: Date} objects'));
}
try {
const keysCorrect = values.reduce((previous, next) => {
return previous && next.quote != undefined && next.valdate != undefined;
}, true);
if(!keysCorrect) {
return respond(new Error('The value property of data should be an array containing {quote: Integer, valdate: Date} objects'));
}
} catch(err) {
return respond(new Error('The value property of data should be an array containing {quote: Integer, valdate: Date} objects'));
}
dbConnection.addPlayerValues(playerId, values)
.then(status => respond(null, status))
.catch(err =>
respond(err));
}
function lookUpPlayerId (msg, respond) {
if(!msg.data)
return respond(new Error('data property must be defined and it should contain the comPlayerId'));
const comPlayerId = msg.data.comPlayerId;
if (!comPlayerId)
return respond(new Error('Please specify the comPlayerId property in the data property of the message'));
dbConnection.lookUpPlayerId(comPlayerId)
.then(playerId => respond(null, playerId))
.catch(err => respond(err));
}
function getPlayerStats (msg, respond) {
if(!msg.data) return respond(new Error('data property must be defined and it should contain the comPlayerId'));
const playerId = msg.data.playerId;
const gameDay = msg.data.gameDay;
const seasonStart = msg.data.seasonStart;
if (!playerId || typeof playerId !== "number") return respond(new Error('Parameter playerId is not specified or is not a number'));
dbConnection.getPlayerStats(playerId, seasonStart, gameDay)
.then(stats => respond(null, stats))
.catch(err => respond(err));
}
function addPlayerStats (msg, respond) {
if(!msg.data) return respond(new Error('data property must be defined and it should contain the comPlayerId'));
const playerId = msg.data.playerId;
const gameDay = msg.data.gameDay;
const seasonStart = msg.data.seasonStart;
const goals = msg.data.goals;
const opponentId = msg.data.opponentId;
const home = msg.data.home;
const cards = msg.data.cards;
const subIn = msg.data.subIn;
const subOut = msg.data.subOut;
const points = msg.data.points;
if (playerId == null || typeof playerId !== "number") return respond(new Error('Parameter playerId is not specified or is not a number'));
if (gameDay ==null || typeof gameDay !== "number") return respond(new Error('Parameter gameDay is not specified or is not a number'));
if (seasonStart == null || typeof seasonStart !== "number") return respond(new Error('Parameter seasonStart is not specified or is not a number'));
if (goals == null || typeof goals !== "number") return respond(new Error('Parameter goals is not specified or is not a number'));
if (!opponentId || typeof opponentId !== "number") return respond(new Error('Parameter opponentId is not specified or is not a number'));
if (typeof(home) !== "boolean") return respond(new Error('Parameter home is not specified or is not a boolean'));
if (cards && !(cards === "red" || cards === "yellow" || cards === "yellow-red")) return respond(new Error('Parameter cards must be either yellow, yellow-red or red but is ' + cards));
if (subIn != null && typeof subIn !== "number") return respond(new Error('Parameter subIn is not a number'));
if (subOut != null && typeof subOut !== "number") return respond(new Error('Parameter subOut is not a number'));
if (points != null && typeof points !== "number") return respond(new Error('Parameter points is not a number'));
dbConnection.addPlayerStats({
playerId,
gameDay,
seasonStart,
goals,
opponentId,
home,
cards,
subIn,
subOut,
points
})
.then(status => respond(undefined, status))
.catch(err => respond(err));
}
function addAllPlayerStats (msg, respond) {
if(!msg.data) return respond(new Error('data property must be defined and it should contain the comPlayerId'));
Promise.all(msg.data.map(playerStat => dbConnection.addPlayerStats(playerStat)))
.then(status => respond(undefined, status))
.catch(err => respond(err));
}
function addGame(msg, respond) {
if(!msg.data) return respond(new Error('data property must be defined and it should contain the comPlayerId'));
const gameDay = msg.data.gameDay;
const seasonStart = msg.data.seasonStart;
const homeScore = msg.data.homeScore;
const guestScore = msg.data.guestScore;
const homeClubId = msg.data.homeClubId;
const guestClubId = msg.data.guestClubId;
if(checkIfNumber(gameDay)) return respond(noExistenceOrNoNumberRejection("gameDay"));
if(checkIfNumber(seasonStart)) return respond(noExistenceOrNoNumberRejection("seasonStart"));
if(checkIfNumber(homeClubId)) return respond(noExistenceOrNoNumberRejection("homeClubId"));
if(checkIfNumber(guestClubId)) return respond(noExistenceOrNoNumberRejection("guestClubId"));
if(homeScore && checkIfNumber(homeScore)) return respond(noNumberRejection("homeScore"));
if(guestScore && checkIfNumber(guestScore)) return respond(noNumberRejection("guestScore"));
dbConnection.addGame({
gameDay,
seasonStart,
homeScore,
guestScore,
homeClubId,
guestClubId
})
.then(status => respond(null, status))
.catch(err => respond(err));
}
function getGames(msg, respond) {
if(!msg.data) return respond(new Error('data property must be defined and it should contain the comPlayerId'));
const seasonStart = msg.data.seasonStart;
const gameDay = msg.data.gameDay;
dbConnection.getGames(seasonStart, gameDay)
.then(games => respond(null, games))
.catch(err => respond(err));
}
function checkIfNumber(number) {
return number == null || typeof number !== "number"
}
function noExistenceOrNoNumberRejection(parameter) {
return new Error('Parameter ' + parameter + ' is not specified or is not a number');
}
function noNumberRejection(parameter) {
return new Error('Parameter ' + parameter + ' is not a number');
}
/*jslint indent: 2, onevar: false, browser: false, regexp: false, browser: true*/
/*globals testCase,
sinon,
assert,
assertSame,
assertEquals,
assertTrue,
assertFalse,
assertNull,
assertException,
assertNoException,
assertUndefined,
assertObject,
assertFunction*/
/**
* @author Christian Johansen (christian@cjohansen.no)
* @license BSD
*
* Copyright (c) 2010 Christian Johansen
*/
testCase("ServerCreateTest", {
tearDown: function () {
this.server.restore();
},
"should return server object": function () {
this.server = sinon.fakeServer.create();
assertObject(this.server);
assert(sinon.fakeServer.isPrototypeOf(this.server));
},
"should provide restore method": function () {
this.server = sinon.fakeServer.create();
assertFunction(this.server.restore);
},
"should fake XMLHttpRequest": sinon.test(function () {
this.stub(sinon, "useFakeXMLHttpRequest").returns({
restore: this.stub()
});
this.server = sinon.fakeServer.create();
assert(sinon.useFakeXMLHttpRequest.called);
}),
"should mirror FakeXMLHttpRequest restore method": sinon.test(function () {
this.server = sinon.fakeServer.create();
var restore = this.stub(sinon.FakeXMLHttpRequest, "restore");
this.server.restore();
assert(restore.called);
})
});
testCase("ServerRequestsTest", {
setUp: function () {
this.server = sinon.fakeServer.create();
},
tearDown: function () {
this.server.restore();
},
"should collect objects created with fake XHR": function () {
var xhrs = [new sinon.FakeXMLHttpRequest(), new sinon.FakeXMLHttpRequest()];
assertEquals(xhrs, this.server.requests);
},
"should collect xhr objects through addRequest": function () {
this.server.addRequest = sinon.spy();
var xhr = new sinon.FakeXMLHttpRequest();
assert(this.server.addRequest.calledWith(xhr));
},
"should observe onSend on requests": function () {
var xhrs = [new sinon.FakeXMLHttpRequest(), new sinon.FakeXMLHttpRequest()];
assertFunction(xhrs[0].onSend);
assertFunction(xhrs[1].onSend);
},
"onSend should call handleRequest with request object": function () {
var xhr = new sinon.FakeXMLHttpRequest();
xhr.open("GET", "/");
sinon.spy(this.server, "handleRequest");
xhr.send();
assert(this.server.handleRequest.called);
assert(this.server.handleRequest.calledWith(xhr));
}
});
testCase("ServerHandleRequestTest", {
setUp: function () {
this.server = sinon.fakeServer.create();
},
tearDown: function () {
this.server.restore();
},
"should respond to synchronous requests": function () {
var xhr = new sinon.FakeXMLHttpRequest();
xhr.open("GET", "/", false);
sinon.spy(xhr, "respond");
xhr.send();
assert(xhr.respond.called);
},
"should not respond to async requests": function () {
var xhr = new sinon.FakeXMLHttpRequest();
xhr.open("GET", "/", true);
sinon.spy(xhr, "respond");
xhr.send();
assertFalse(xhr.respond.called);
}
});
testCase("ServerRespondWithTest", {
setUp: function () {
this.server = sinon.fakeServer.create();
this.getRootAsync = new sinon.FakeXMLHttpRequest();
this.getRootAsync.open("GET", "/", true);
this.getRootAsync.send();
sinon.spy(this.getRootAsync, "respond");
this.postRootAsync = new sinon.FakeXMLHttpRequest();
this.postRootAsync.open("POST", "/", true);
this.postRootAsync.send();
sinon.spy(this.postRootAsync, "respond");
this.getRootSync = new sinon.FakeXMLHttpRequest();
this.getRootSync.open("GET", "/", false);
this.getPathAsync = new sinon.FakeXMLHttpRequest();
this.getPathAsync.open("GET", "/path", true);
this.getPathAsync.send();
sinon.spy(this.getPathAsync, "respond");
this.postPathAsync = new sinon.FakeXMLHttpRequest();
this.postPathAsync.open("POST", "/path", true);
this.postPathAsync.send();
sinon.spy(this.postPathAsync, "respond");
},
tearDown: function () {
this.server.restore();
},
"should respond to queued async requests": function () {
this.server.respondWith("Oh yeah! Duffman!");
this.server.respond();
assert(this.getRootAsync.respond.called);
assertEquals([200, {}, "Oh yeah! Duffman!"], this.getRootAsync.respond.args[0]);
},
"should respond to all queued async requests": function () {
this.server.respondWith("Oh yeah! Duffman!");
this.server.respond();
assert(this.getRootAsync.respond.called);
assert(this.getPathAsync.respond.called);
},
"should respond with status, headers, and body": function () {
var headers = { "Content-Type": "X-test" };
this.server.respondWith([201, headers, "Oh yeah!"]);
this.server.respond();
assertEquals([201, headers, "Oh yeah!"], this.getRootAsync.respond.args[0]);
},
"should handle responding with empty queue": function () {
delete this.server.queue;
var server = this.server;
assertNoException(function () {
server.respond();
});
},
"should respond to sync request with canned answers": function () {
this.server.respondWith([210, { "X-Ops": "Yeah" }, "Body, man"]);
this.getRootSync.send();
assertEquals(210, this.getRootSync.status);
assertEquals({ "x-ops": "Yeah" }, this.getRootSync.getAllResponseHeaders());
assertEquals("Body, man", this.getRootSync.responseText);
},
"should respond to sync request with 404 if no response is set": function () {
this.getRootSync.send();
assertEquals(404, this.getRootSync.status);
assertEquals({}, this.getRootSync.getAllResponseHeaders());
assertEquals("", this.getRootSync.responseText);
},
"should respond to async request with 404 if no response is set": function () {
this.server.respond();
assertEquals([404, {}, ""], this.getRootAsync.respond.args[0]);
},
"should respond to specific URL": function () {
this.server.respondWith("/path", "Duffman likes Duff beer");
this.server.respond();
assertEquals([404, {}, ""], this.getRootAsync.respond.args[0]);
assertEquals([200, {}, "Duffman likes Duff beer"], this.getPathAsync.respond.args[0]);
},
"should respond to URL matched by regexp": function () {
this.server.respondWith(/^\/p.*/, "Regexp");
this.server.respond();
assertEquals([200, {}, "Regexp"], this.getPathAsync.respond.args[0]);
},
"should not respond to URL not matched by regexp": function () {
this.server.respondWith(/^\/p.*/, "No regexp match");
this.server.respond();
assertEquals([404, {}, ""], this.getRootAsync.respond.args[0]);
},
"should respond to all URLs matched by regexp": function () {
this.server.respondWith(/^\/.*/, "Match all URLs");
this.server.respond();
assertEquals([200, {}, "Match all URLs"], this.getRootAsync.respond.args[0]);
assertEquals([200, {}, "Match all URLs"], this.getPathAsync.respond.args[0]);
},
"should respond to all requests when match URL is falsy": function () {
this.server.respondWith("", "Falsy URL");
this.server.respond();
assertEquals([200, {}, "Falsy URL"], this.getRootAsync.respond.args[0]);
assertEquals([200, {}, "Falsy URL"], this.getPathAsync.respond.args[0]);
},
"should respond to all GET requests": function () {
this.server.respondWith("GET", "", "All GETs");
this.server.respond();
assertEquals([200, {}, "All GETs"], this.getRootAsync.respond.args[0]);
assertEquals([200, {}, "All GETs"], this.getPathAsync.respond.args[0]);
assertEquals([404, {}, ""], this.postRootAsync.respond.args[0]);
assertEquals([404, {}, ""], this.postPathAsync.respond.args[0]);
},
"should respond to all 'get' requests (case-insensitivity)": function () {
this.server.respondWith("get", "", "All GETs");
this.server.respond();
assertEquals([200, {}, "All GETs"], this.getRootAsync.respond.args[0]);
assertEquals([200, {}, "All GETs"], this.getPathAsync.respond.args[0]);
assertEquals([404, {}, ""], this.postRootAsync.respond.args[0]);
assertEquals([404, {}, ""], this.postPathAsync.respond.args[0]);
},
"should respond to all PUT requests": function () {
this.server.respondWith("PUT", "", "All PUTs");
this.server.respond();
assertEquals([404, {}, ""], this.getRootAsync.respond.args[0]);
assertEquals([404, {}, ""], this.getPathAsync.respond.args[0]);
assertEquals([404, {}, ""], this.postRootAsync.respond.args[0]);
assertEquals([404, {}, ""], this.postPathAsync.respond.args[0]);
},
"should respond to all POST requests": function () {
this.server.respondWith("POST", "", "All POSTs");
this.server.respond();
assertEquals([404, {}, ""], this.getRootAsync.respond.args[0]);
assertEquals([404, {}, ""], this.getPathAsync.respond.args[0]);
assertEquals([200, {}, "All POSTs"], this.postRootAsync.respond.args[0]);
assertEquals([200, {}, "All POSTs"], this.postPathAsync.respond.args[0]);
},
"should respond to all POST requests to /path": function () {
this.server.respondWith("POST", "/path", "All POSTs");
this.server.respond();
assertEquals([404, {}, ""], this.getRootAsync.respond.args[0]);
assertEquals([404, {}, ""], this.getPathAsync.respond.args[0]);
assertEquals([404, {}, ""], this.postRootAsync.respond.args[0]);
assertEquals([200, {}, "All POSTs"], this.postPathAsync.respond.args[0]);
},
"should respond to all POST requests matching regexp": function () {
this.server.respondWith("POST", /^\/path(\?.*)?/, "All POSTs");
this.server.respond();
assertEquals([404, {}, ""], this.getRootAsync.respond.args[0]);
assertEquals([404, {}, ""], this.getPathAsync.respond.args[0]);
assertEquals([404, {}, ""], this.postRootAsync.respond.args[0]);
assertEquals([200, {}, "All POSTs"], this.postPathAsync.respond.args[0]);
},
"should not respond to aborted requests": function () {
this.server.respondWith("/", "That's my homepage!");
this.getRootAsync.aborted = true;
this.server.respond();
assertFalse(this.getRootAsync.respond.called);
},
"should reset requests": function () {
this.server.respondWith("/", "That's my homepage!");
this.server.respond();
assertEquals([], this.server.queue);
},
"should notify all requests when some throw": function () {
this.getRootAsync.respond = function () {
throw new Error("Oops!");
};
this.server.respondWith("");
this.server.respond();
assertEquals([200, {}, ""], this.getPathAsync.respond.args[0]);
assertEquals([200, {}, ""], this.postRootAsync.respond.args[0]);
assertEquals([200, {}, ""], this.postPathAsync.respond.args[0]);
}
});
testCase("ServerRespondFakeHTTPVerbTest", {
setUp: function () {
this.server = sinon.fakeServer.create();
this.request = new sinon.FakeXMLHttpRequest();
this.request.open("post", "/path", true);
this.request.send("_method=delete");
sinon.spy(this.request, "respond");
},
tearDown: function () {
this.server.restore();
},
"should not respond to DELETE request with _method parameter": function () {
this.server.respondWith("DELETE", "", "");
this.server.respond();
assertEquals([404, {}, ""], this.request.respond.args[0]);
},
"should respond to 'fake' DELETE request": function () {
this.server.fakeHTTPMethods = true;
this.server.respondWith("DELETE", "", "OK");
this.server.respond();
assertEquals([200, {}, "OK"], this.request.respond.args[0]);
},
"should not respond to POST when faking DELETE": function () {
this.server.fakeHTTPMethods = true;
this.server.respondWith("POST", "", "OK");
this.server.respond();
assertEquals([404, {}, ""], this.request.respond.args[0]);
},
"should not fake method when not POSTing": function () {
this.server.fakeHTTPMethods = true;
this.server.respondWith("DELETE", "", "OK");
var request = new sinon.FakeXMLHttpRequest();
request.open("GET", "/");
request.send();
request.respond = sinon.spy();
this.server.respond();
assertEquals([404, {}, ""], request.respond.args[0]);
},
"should customize HTTP method extraction": function () {
this.server.getHTTPMethod = function (request) {
return "PUT";
};
this.server.respondWith("PUT", "", "OK");
this.server.respond();
assertEquals([200, {}, "OK"], this.request.respond.args[0]);
}
});