Convert callback to thunk - node.js

I am using mongoose with koa.js (maybe a bad choice but had to stick with it).
My initial callback function was :
var _project = yield parse(this);
var userdetails = this.req.user;
var that = this ;
//=============================================================
//FInd a user , check the project name exists under the user, if not then create one
//=============================================================
User.findOne({ '_id': userdetails._id }, function (err, user) {
if (err) {
this.body = "please login again , your session seems to have expired"
} console.log(user.projects.owner.indexOf(_project.name));
if(user.projects.owner.indexOf(_project.name) == -1) { //This means the project is not yet created
var temp_project = new Project(_project);
temp_project.save(function save() {
if(err) {
that.body = "Project coudn't be saved, Please try again sometime later";
} else {
user.projects.owner.push(_project.name);
user.save(function save() {
if (err) {
that.body = "This error is highly unlikely, yet if you see this .Please report this issue";
}
});
that.body = temp_project;
}
});
}
if(user.projects.owner.indexOf(_project.name) >= 0) { //THis means the project exists
that.body = "You have already created a project with same name, please use a different name";
console.log("you reached till here");
}
});
This should have worked in normal express world but later I realised that I need to rewrite in the forms of thunks so my current attemp is
function userfindONE(err, user) {
if (err) {
return "please login again , your session seems to have expired"
}
if(user.projects.owner.indexOf(tproject.name) == -1) { //This means the project is not yet created
var temp_project = new Project(tproject);
temp_project.save(function save() {
if(err) {
return "Project coudn't be saved, Please try again sometime later";
} else {
user.projects.owner.push(tproject.name);
user.save(function save() {
if (err) {
return "This error is highly unlikely, yet if you see this .Please report this issue";
}
});
return temp_project;
}
});
}
if(user.projects.owner.indexOf(tproject.name) >= 0) { //THis means the project exists
return "You have already created a project with same name, please use a different name";
} else return "nothing is matching";
}
function userfindone(userdetails) {
return function(cb) {
User.findOne({ '_id': userdetails._id }, cb);
};
}
var userdetails = this.req.user;
var tproject = yield parse(this);
But this returns the user details from the User.findone from the first mongoose call.
and anything else seems to have ignored. Thanks
this.body = yield userfindone(userdetails)(userfindONE) ;

Take a look at node-thunkify. It should be as simple as wrapping your schema's functions with it.

With Mongoose 3.9.x you can simply yield user.save(), check in your package.json you have installed the unstable release.

Related

Node JS not updating "global variable" [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
My intended use of the code is to check whether the database have a username and password that is passed to the function in the form of object User.
I initialize the success variable to false. And then I say if I find the record, then I will set it to true. However, the success variable is still false even when the record is found. The variable seems not be updating. Why?
Also, How can I pass back the whole fetcheduser result while I can indicate whether the record is found or not foun? Many thanks
LoginSuccess : function (User) {
var success = false;
function isEmptyObject(obj) {
return !Object.keys(obj).length;
}
function isEmptyObject(obj) {
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
return false;
}
}
return true;
}
var sql = require('mssql');
var config = require('./configuration/sqlconfig');
var fetcheduser;
sql.connect(config).then(function () {
console.log('Connected to DB');
new sql.Request().query("SELECT * FROM dbo.LocalUser WHERE Username = '" + User.username + "' AND Password = '" + User.password + "';")
.then(function (recordset) {
if (isEmptyObject(recordset)) {
console.log("The User does not exist");
} else {
fetcheduser = JSON.parse(JSON.stringify(recordset));
success = true;
console.log("The user is existed.");
}
}).catch(function (err) {
//When errors come
});
});
return success;
}
You'll need to return your Promise in order to get the correct success state. Like so...
function LoginSuccess() {
var success = false;
return sql.connect(config)
.then(() => {
return new sql.Request().query(...).then(
() => success = true,
() => success = false
);
})
.then(() => {
return success;
});
}
LoginSuccess().then(success => ...);
Actually - variable is updating, but way too late - after you returned it. Try to make a result = { success: false } and check the result immediately after return and 5 secs later (or whatever appropriate), and you will see that it has changed: setTimeout(() => console.log(result), 5000)
Anyways, for production, go for the promise solution. Node 7.6 has finally now async/await, so you can get rid of the ugly ...then workarounds.

Mongoose custom validation failing

In my application I am trying to run some custom validations on mongoose, all I want is to be able to make sure that ratings from a particular user should not exceed more than once, I have tried a couple of things, and the code to begin with return true and false correctly but the error is not triggered. Here is my code
RatingSchema.path('email').validate(function (email) {
var Rating = mongoose.model('Rating');
//console.log('i am being validated')
//console.log('stuff: ' + this.email+ this.item)
Rating.count({email: this.email, item: this.item},function(err,count){
if(err){
console.log(err);
}
else{
if(count===0){
//console.log(count)
return true;
}
else {
//console.log('Count: in else(failing)'+ count)
return false;
}
}
});
},'Item has been already rated by you')
When defining a validator that performs an asynchronous operation (like your Rating.count call), your validator function needs to accept a second parameter which is a callback that you call to provide the true or false result as you can't just return async results.
RatingSchema.path('email').validate(function (email, respond) {
var Rating = mongoose.model('Rating');
Rating.count({email: this.email, item: this.item},function(err,count){
if(err){
console.log(err);
}
else{
if(count===0){
respond(true);
}
else {
respond(false);
}
}
});
},'Item has been already rated by you');

Error "Undefined is not a function " Using callback node.JS

I am trying to save a new Document (user) in my MongoDb and I use callback. The code runs and goes until save the user, but after that I get an error.So I can save user. I have the following code:
function saveUser(userName, socialMediaType, socialMediaID, setDocNumber, callback){
var user;
if(socialMediaType == "fbUID"){
user = new users({
userName: userName,
userEmail: 'userEmail',
teams:[],
fbUID : socialMediaID
});
}else
if(socialMediaType =="google"){
//do the same
}
var query = {}
query["'"+ socialMediaType +"'" ] = socialMediaID
users.findOne(query, function(err, userFound){
if (err) { // err in query
log.d("Error in query FoundUser", err)
log.d("User Found", userFound)
}else
if(userFound == undefined){ //if user does not exist
user.save(function(err, user){
if(err) return console.error(err);
log.d("user saved", user);
currentSession = sessionOBJ.login(user._id, socialMediaID);
callback(currentSession,"created")
});
}else{
currentSession = sessionOBJ.login(userFound._id, socialMediaID);
callback(currentSession,"logged")
}
});
}
I call the function above through this code:
f(fbUID !== undefined){
userModelOBJ.saveUser(userName,"fbUID", fbUID, function(currentSession, status) {
res.send({"status":status,
"sessionID": currentSession.sessionID,
"expires" : currentSession.date});
});
I am getting this error :
The error is in the line :
callback(currentSession,"created")
What could be the problem?
I already did many researchers but this is a specific case.
Your saveUser() call is missing the setDocNumber argument. It looks like you're not using it in your code though, so you might be able to safely remove it. If you are using it somewhere else (that you haven't shown) then you need to do some argument checking at the top of saveUser() to support optional arguments.

Callback hell in nodejs?

In below code am I in callbackhell? How to overcome such scenario without using any async modules in pure javascript?
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
The above code is copied in multiple location to make code work as expected.
function processInviteEmails(email_list, user_id, emailCallBack, completionCallback){
function checkEmail(email){
try {
check(email).isEmail();
//is valid email
checkConnected(email, user_id, function(connect_status, user_row, user_meta_row, connect_row){
var e_data;
//insert to connect and send msg to queue
if(connect_status === 'not connected'){
var cur_date = moment().format('YYYY-MM-DD');
var dbData = {
"first_name": '',
"last_name": '',
"email": email,
"user_id": user_id,
"status": "invited",
"unsubscribe_token": crypto.randomBytes(6).toString('base64'),
"created": cur_date,
"modified": cur_date
};
ConnectModel.insert(dbData, function(result){
if (result.insertId > 0) {
//send to email queue
//Queue Email
MailTemplateModel.getTemplateData('invitation', function(res_data){
if(res_data.status === 'success'){
var unsubscribe_hash = crypto.createHash("md5")
.update(dbData.unsubscribe_token + email)
.digest('hex');
var unsubscribe_link = app.locals.SITE_URL+'/unsubscribe/' + result.insertId + '/' + unsubscribe_hash;
var template_row = res_data.template_row;
var user_full_name = user_row.user_firstname+' '+ user_row.user_lastname;
var invitation_link = 'http://'+user_row.url_alias+'.'+ app.locals.SITE_DOMAIN;
var mailOptions = {
"type": 'invitation',
"to": dbData.email,
"from_name" : user_full_name,
"subject": template_row.message_subject
.replace('[[USER]]', user_full_name),
"text": template_row.message_text_body
.replace('[[USER]]', user_full_name)
.replace('[[INVITATION_LINK]]', invitation_link)
.replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link),
"html": template_row.message_body
.replace('[[USER]]', user_full_name)
.replace('[[INVITATION_LINK]]', invitation_link)
.replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link)
};
mailOptions = JSON.stringify(mailOptions);
//send email to queue
sqsHelper.addToQueue(cfg.sqs_invitation_url, mailOptions, function(data){
if(data){
e_data = null;
}
else{
e_data = new Error('Unable to Queue ');
}
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
});
}
else{
e_data = new Error('Unable to get email template');
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
}
});
}
else{
e_data = new Error('Unable to Insert connect');
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
}
});
}
else{
e_data = new Error('Already connected');
emailCallBack(e_data, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
}
});
} catch (e) {
//invalid email
emailCallBack(e, email);
if (email_list.length) {
checkEmail(email_list.pop());
} else {
completionCallback();
}
}
}
checkEmail(email_list.pop());
}
Yes you are in callback hell. The solution assuming you don't want to use async (which I doubt you can justify other than prejudice) consists of:
1) Make more top-level functions. Each function should perform either 1 or 2 IO operations as a rule of thumb.
2) Call those functions, making your code follow a pattern of a long list of short core functions organized into business logic by a small list of control flow "glue" functions.
Instead of:
saveDb1 //lots of code
saveDb2 //lots of code
sendEmail //lots of code
Aim for:
function saveDb1(arg1, arg2, callback) {//top-level code}
function saveDb2(arg1, arg2, callback) {//top-level code}
function sendEmail(arg1, arg2, callback) {//top-level code}
function businessLogic(){//uses the above to get the work done}
3) Use more function arguments instead of relying so much on closures
4) Emit events and DECOUPLE YOUR CODE! See how you have nested code writing stuff to the database and then building an email and adding it to a queue? Don't you see how those two do not need to exist one on top of the other? Emails lend themselves very well to a core business logic emitting events and an email module listening to those events and queueing the mail.
5) Decouple application-level service connection code from specific transaction business logic. Dealing with connections to network services should be handled more broadly and not embedded with a specific set of business logic.
6) Read other modules for examples
As to should you use an async library, you can and should make up your own mind about that but AFTER you know, and know pretty well, each and every one of these approaches:
callbacks and basic functional javascript techniques
events
promises
Helper libraries (async, step, nimble, etc)
Any serious node.js developer knows how to use and work within ALL of those paradigms. Yes, everyone has their favored approach and maybe some nerd rage about the non-favored approaches, but none of these are difficult and it's bad to get set in your decision without being able to point to some non-trivial code you wrote from scratch in each paradigm. Also, you should try several helper libraries and understand how they work and why they are going to save you boilerplate. Studying the work of Tim Caswell's Step or Caolan McMahon's async is going to be very enlightening. Have you seen the everyauth source code's use of promises? I don't like it personally but I surely have to admit that the author has squeezed damn near every last bit of repetition out of that library, and the way he uses promises will turn your brain into a pretzel. These people are wizards with much to teach. Don't scoff at those libraries just for hipster points or whatever.
Also a good external resource is callbackhell.com.
"If you try to code bussiness db login using pure node.js, you go straight to callback hell"
I've recently created a simple abstraction named WaitFor to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor
check the database example:
Database example (pseudocode)
pure node.js (mild callback hell):
var db = require("some-db-abstraction");
function handleWithdrawal(req,res){
try {
var amount=req.param("amount");
db.select("* from sessions where session_id=?",req.param("session_id"),function(err,sessiondata) {
if (err) throw err;
db.select("* from accounts where user_id=?",sessiondata.user_ID),function(err,accountdata) {
if (err) throw err;
if (accountdata.balance < amount) throw new Error('insufficient funds');
db.execute("withdrawal(?,?),accountdata.ID,req.param("amount"), function(err,data) {
if (err) throw err;
res.write("withdrawal OK, amount: "+ req.param("amount"));
db.select("balance from accounts where account_id=?", accountdata.ID,function(err,balance) {
if (err) throw err;
res.end("your current balance is " + balance.amount);
});
});
});
});
}
catch(err) {
res.end("Withdrawal error: " + err.message);
}
Note: The above code, although it looks like it will catch the exceptions, it will not.
Catching exceptions with callback hell adds a lot of pain, and i'm not sure if you will have the 'res' parameter
to respond to the user. If somebody like to fix this example... be my guest.
using wait.for:
var db = require("some-db-abstraction"), wait=require('wait.for');
function handleWithdrawal(req,res){
try {
var amount=req.param("amount");
sessiondata = wait.forMethod(db,"select","* from session where session_id=?",req.param("session_id"));
accountdata= wait.forMethod(db,"select","* from accounts where user_id=?",sessiondata.user_ID);
if (accountdata.balance < amount) throw new Error('insufficient funds');
wait.forMethod(db,"execute","withdrawal(?,?)",accountdata.ID,req.param("amount"));
res.write("withdrawal OK, amount: "+ req.param("amount"));
balance=wait.forMethod(db,"select","balance from accounts where account_id=?", accountdata.ID);
res.end("your current balance is " + balance.amount);
}
catch(err) {
res.end("Withdrawal error: " + err.message);
}
Note: Exceptions will be catched as expected.
db methods (db.select, db.execute) will be called with this=db
Your Code
In order to use wait.for, you'll have to STANDARDIZE YOUR CALLBACKS to function(err,data)
If you STANDARDIZE YOUR CALLBACKS, your code might look like:
//run in a Fiber
function processInviteEmails(email_list, user_id, emailCallBack, completionCallback){
while (email_list.length) {
var email = email_list.pop();
try {
check(email).isEmail(); //is valid email or throw
var connected_data = wait.for(checkConnected,email,user_id);
if(connected_data.connect_status !== 'not connected') throw new Error('Already connected');
//insert to connect and send msg to queue
var cur_date = moment().format('YYYY-MM-DD');
var dbData = {
"first_name": '',
"last_name": '',
"email": email,
"user_id": user_id,
"status": "invited",
"unsubscribe_token": crypto.randomBytes(6).toString('base64'),
"created": cur_date,
"modified": cur_date
};
result = wait.forMethod(ConnectModel,'insert',dbData);
// ConnectModel.insert shuold have a fn(err,data) as callback, and return something in err if (data.insertId <= 0)
//send to email queue
//Queue Email
res_data = wait.forMethod(MailTemplateModel,'getTemplateData','invitation');
// MailTemplateModel.getTemplateData shuold have a fn(err,data) as callback
// inside getTemplateData, callback with err=new Error('Unable to get email template') if (data.status !== 'success')
var unsubscribe_hash = crypto.createHash("md5")
.update(dbData.unsubscribe_token + email)
.digest('hex');
var unsubscribe_link = app.locals.SITE_URL+'/unsubscribe/' + result.insertId + '/' + unsubscribe_hash;
var template_row = res_data.template_row;
var user_full_name = user_row.user_firstname+' '+ user_row.user_lastname;
var invitation_link = 'http://'+user_row.url_alias+'.'+ app.locals.SITE_DOMAIN;
var mailOptions = {
"type": 'invitation',
"to": dbData.email,
"from_name" : user_full_name,
"subject": template_row.message_subject
.replace('[[USER]]', user_full_name),
"text": template_row.message_text_body
.replace('[[USER]]', user_full_name)
.replace('[[INVITATION_LINK]]', invitation_link)
.replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link),
"html": template_row.message_body
.replace('[[USER]]', user_full_name)
.replace('[[INVITATION_LINK]]', invitation_link)
.replace('[[UNSUBSCRIBE_LINK]]', unsubscribe_link)
};
mailOptions = JSON.stringify(mailOptions);
//send email to queue ... callback(err,data)
wait.forMethod(sqsHelper,'addToQueue',cfg.sqs_invitation_url, mailOptions);
} catch (e) {
// one of the callback returned err!==null
emailCallBack(e, email);
}
} // loop while length>0
completionCallback();
}
// run the loop in a Fiber (keep node spinning)
wait.launchFiber(processInviteEmails,email_list, user_id, emailCallBack, completionCallback);
see? no callback hell
I've put another solution in my blog. It is ugly but it is the most readable thing I could do with pure javascript.
var flow1 = new Flow1(
{
execute_next_step: function(err) {
if (err) {
console.log(err);
};
}
}
);
flow1.execute_next_step();
function Flow1(parent_flow) {
this.execute_next_step = function(err) {
if (err) return parent_flow.execute_next_step(err);
if (!this.next_step) this.next_step = 'START';
console.log('Flow1:', this.next_step);
switch (this.next_step) {
case 'START':
this.next_step = 'FIRST_ASYNC_TASK_FINISHED';
firstAsyncTask(this.execute_next_step.bind(this));
break;
case 'FIRST_ASYNC_TASK_FINISHED':
this.firstAsyncTaskReturn = arguments[1];
this.next_step = 'ANOTHER_FLOW_FINISHED';
this.another_flow = new AnotherFlow(this);
this.another_flow.execute_next_step();
break;
case 'ANOTHER_FLOW_FINISHED':
this.another_flow_return = arguments[1];
this.next_step = 'FINISH';
this.execute_next_step();
break;
case 'FINISH':
parent_flow.execute_next_step();
break;
}
}
}
function AnotherFlow(parent_flow) {
this.execute_next_step = function(err) {
if (err) return parent_flow.execute_next_step(err);
if (!this.next_step) this.next_step = 'START';
console.log('AnotherFlow:', this.next_step);
switch (this.next_step) {
case 'START':
console.log('I dont want to do anything!. Calling parent');
parent_flow.execute_next_step();
break;
}
}
}

NodeJS less visible callbacks and more structure

One of the advantages of NodeJS is its async and non-blocking I/O, which in my case is great on the one hand, but breaks my neck every day on the other hand.
I consider myself a NodeJS / Async novice and I often end up having such code:
function(req, res) {
req.assert("name", "Lobbyname is required").notEmpty();
req.assert("name", "Lobbyname length should be between 4 and 64 characters").len(4, 64);
req.assert("game", "Game not found").isInt();
req.sanitize("game").toInt();
var userId = req.user.id;
var errors = req.validationErrors();
var pg_errors = [];
var games = null;
if (errors) {
console.log(errors);
client.query("SELECT * FROM games", function(err, result) {
if (!err) {
games = result.rows;
res.render("lobby/create", {
title: "Create a new lobby",
games: games,
errors: errors.toString()
});
}
else {
res.send("error");
}
});
}
else {
errors = null;
client.query("SELECT COUNT(*) as in_lobbies FROM users u RIGHT JOIN lobby_userlist ul ON ul.user_id = u.id WHERE u.id = $1", [userId], function(err, result) {
if (!err) {
console.log(result.rows[0]);
if (result.rows[0].in_lobbies < 1) {
client.query("SELECT COUNT(*) as hosting_lobbies FROM lobbies WHERE owner = $1", [userId], function(err, result) {
if (!err) {
if (result.rows[0].hosting_lobbies < 1) {
client.query("INSERT INTO lobbies(name, game, owner) VALUES($1, $2, $3)", [req.param("name"), req.param("game"), userId], function(err, result) {
if (!err) {
res.redirect("/lobby");
}
else {
pg_errors.push(err);
console.log(err);
}
});
}
else {
errors = "You can only host one lobby at a time";
}
}
else {
pg_errors.push(err);
client.query("SELECT * FROM games", function(err, result) {
if (!err) {
games = result.rows;
res.render("lobby/create", {
title: "Create a new lobby",
games: games,
errors: errors
});
}
else {
pg_errors.push(err);
}
});
}
});
}
else {
pg_errors.push(err);
}
}
});
console.log("pg_errors");
console.log(pg_errors);
console.log("pg_errors _end");
if (pg_errors.length < 1) {
console.log("no errors");
}
else {
console.log(pg_errors);
res.send("error service operation failed");
}
}
}
This an example I have written using the following npm packages:
pg (native)
express
express-validator (middleware of node-validator)
passport (auth middleware)
Checking whether the input given by the user is valid or not is the least problem, I have this checks where I assert the variables and give back a rendered version of the page printing out the errors to the user.
BUT if we pass the validation errors in the first place we assume the "lobby" is ready to be inserted into the database, before I want to ensure that the user has no other lobby open and is not member of another lobby.
Well now I end up putting one query into another and theoretically I would have to put my view render function (res.render()) into every query callback if the query encounters an error or returns a result which inidicates that the user is not allowed to create a lobby.
I don't want that and it doesn't seem very practicable.
I tried removing the render logic and every other logic from the query callbacks and instead let the query callbacks set error arrays or variables which would indicate a success or a failure and below my query code I would check if(errors) renderPageWithErrors.
This lead to strange errors due to the async behaviour of nodejs in which case res.redirect() was called after res.render() and stuff like that.
I had to move my res.render back into the query callbacks.
Is there a proper way of doing this?
You might want to look into an async library such as https://github.com/caolan/async. It helps structure async code so that it doesn't turn into a mess like this. There are different methods depending on your requirements from simple series and parallel execution to things like waterfall to auto which does dependency tracking.
async.auto({
get_data: function(callback){
// async code to get some data
},
make_folder: function(callback){
// async code to create a directory to store a file in
// this is run at the same time as getting the data
},
write_file: ['get_data', 'make_folder', function(callback){
// once there is some data and the directory exists,
// write the data to a file in the directory
callback(null, filename);
}],
email_link: ['write_file', function(callback, results){
// once the file is written let's email a link to it...
// results.write_file contains the filename returned by write_file.
}]
}, function(err) {
// everything is done or an error occurred
});
The other nice thing it does is consolidate all errors into a single callback. That way you only have to handle errors in one place instead of them sprinkled throughout your code.
You might want to check for https://github.com/0ctave/node-sync library as well. It's a syntax sugar for nodejs Fibers, a way to write asynchronous code in a traditional way without breaking nodejs event loop model. There are a lot of discussions about pros and cons of using Fibers, but I prefer code readability and ease of development over potential small resource usage increase.
I don't know all of your code logic, but function above can look something like this:
function(req, res) {
Sync(function() {
req.assert("name", "Lobbyname is required").notEmpty();
req.assert("name", "Lobbyname length should be between 4 and 64 characters").len(4, 64);
req.assert("game", "Game not found").isInt();
req.sanitize("game").toInt();
var userId = req.user.id;
var errors = req.validationErrors();
var pg_errors = [];
var games = null;
if (errors) {
console.log(errors);
var games = client.query.sync(client, "SELECT * FROM games").rows;
games = result;
res.render("lobby/create", {
title: "Create a new lobby",
games: games,
errors: errors.toString()
});
}
else {
errors = null;
var result = client.query.sync(client, "SELECT COUNT(*) as in_lobbies FROM users u RIGHT JOIN lobby_userlist ul ON ul.user_id = u.id WHERE u.id = $1", [userId]);
console.log(result.rows[0]);
if (result.rows[0].in_lobbies < 1) {
var result = client.query.sync(client, "SELECT COUNT(*) as hosting_lobbies FROM lobbies WHERE owner = $1", [userId]);
if (result.rows[0].hosting_lobbies < 1) {
var res = client.query.sync(clien, "INSERT INTO lobbies(name, game, owner) VALUES($1, $2, $3)", [req.param("name"), req.param("game"), userId]);
res.redirect("/lobby");
}
else {
errors = "You can only host one lobby at a time";
}
}
else {
var games = client.query.sync(client, "SELECT * FROM games").rows;
res.render("lobby/create", {
title: "Create a new lobby",
games: games,
errors: errors
});
};
}
}, function(err) {
if(err) {
// do your error handling here
}
});
}

Resources