how to bypass multiple then in of mongoose - node.js

I Don't want to make checks as if (!isPresent) then do this ....
Is their any way to bypass all the then when my work is complete
var isPresent=false;
myPromise
.then((employee) => {
if (employee) {
// throw 'employee already exist';
isPresent = true;
return res.data(mapper.toFullModel(employee));
}
return model;
});
.then(model => {
if (!isPresent) {
return new db.employee(model).save();
}
})
.then(employee => {
if (!isPresent) {
employee.token = auth.getToken(employee);
return employee.save();
}
})
.then(employee => {
if (!isPresent) {
res.data(mapper.toFullModel(employee));
}
})
.catch(err => {
res.failure(err);
});

You can rewrite your promise chain so the second part of it gets nested:
myPromise.then(employee => {
if (employee) {
return res.data(mapper.toFullModel(employee));
}
return new db.employee(model).save().then(employee => {
employee.token = auth.getToken(employee);
return employee.save();
}).then(employee => {
return res.data(mapper.toFullModel(employee));
});
}).catch(err => {
res.failure(err);
});

Related

telegraf how to check if user is admin?

i have this code:
function isAdmin(idOfChat, IdOfUser, ctx) {
//function
return isAdminBoolean
}
bot.command("test", ctx => {
if (isAdmin(ctx.message.chat.id, ctx.message.from.id) == true) {
ctx.reply("Admin")
}else{
ctx.reply("._.")
}
})
how to make it work?
sorry for my bad English)))
You should re-write your method as a promise (because Telegraf queries from Telegram API, so, your isAdmin method could be like this)
function isAdmin(idOfChat, IdOfUser, ctx) {
return new Promise((resolve, reject) => {
//Get user information first
ctx.telegram.getChatMember(idOfChat, IdOfUser).then((user) => {
//Then check if user is admin (or creator)
resolve(user.status == "administrator" || user.status == "creator");
})
.catch((error) => {
//Reject if it's an error
reject(error);
});
});
}
Then, for use it into your main function, you should have to handle it like this:
bot.command("test", ctx => {
isAdmin(ctx.message.chat.id, ctx.message.from.id, ctx).then((result) => {
if (result) {
ctx.reply("Admin");
} else {
ctx.reply("._.");
}
})
.catch((error) => {
ctx.reply("An error has ocurred trying to get user rank: " + JSON.stringify(error));
});
});

How to stub the same method in two test-cases using Sinon?

I am using Node, Mongoose, Sinon, Mocha.
In the DAO layer, I have methods named methodA, methodB. In the service layer, I have servMethodA (calls methodA), servMethodB (calls methodB), servMethodC. Now, servMethodC calls the methodA from DAO and then I have a call to methodB nested in it.
In the test cases for the service layer, I have already stubbed methodA and methodB. How do I stub them again for the test-case for servMethodC?
These are my service methods.
function findLikeByPostIdAndUserId(postId, userId) {
return new Promises((resolve, reject) => {
likeDislikeDao.findLikeByPostIdAndUserId(postId, userId).
then((data) => {
resolve(data);
})
.catch((error) => {
reject(error);
});
});
}
function findDislikeByPostIdAndUserId(postId, userId) {
return new Promises((resolve, reject) => {
likeDislikeDao.findDislikeByPostIdAndUserId(postId, userId).
then((data) => {
resolve(data);
})
.catch((error) => {
reject(error);
});
});
}
function saveLike(like) {
console.log(like);
return new Promises((resolve, reject) => {
console.log(data);
likeDislikeDao.findLikeByPostIdAndUserId(like.postId, like.userId).
then((data) => {
if (!data) {
likeDislikeDao.findDislikeByPostIdAndUserId(like.postId, like.userId).
then((dislikeData) => {
if (!dislikeData) {
likeDislikeDao.saveLike(like).
then((data) => {
resolve(data);
});
}
else {
likeDislikeDao.deleteDislike(dislikeData._id)
.then((data) => {
likeDislikeDao.saveLike(like).
then((data) => {
resolve(data);
});
});
}
});
}
else {
likeDislikeDao.deleteLike(data._id)
.then((data) => {
//likeDislikeDao.saveLike(like).
// then((data) => {
// resolve(data);
// });
resolve(data);
});
}
})
.catch((error) => {
reject(error);
});;
});
}
Here are my individual test cases.
describe('saveLike', function () {
it('should add a like', function () {
var stub = sinontwo.stub(likeDislikeDao, 'saveLike');
stub.withArgs(newLike).callsFake(() => {
return Promise.resolve(newLike);
});
var stubtwo = sinontwo.stub(likeDislikeDao, 'saveDislike');
stubtwo.withArgs(newDislike).callsFake(() => {
return Promise.resolve(newDislike);
});
const stubthree = sinontwo.stub(likeDislikeDao, 'findLikeByPostIdAndUserId');
stubthree.callsFake(() => {
return Promise.resolve(like);
});
const stubfour = sinontwo.stub(likeDislikeDao, 'findDislikeByPostIdAndUserId');
stubfour.callsFake(() => {
return Promise.resolve(dislike);
});
likeDislikeService.saveLike(newLike).then(response => {
console.log('1 -> ');
console.log(response);
assert.length(response, 1);
});
stub.withArgs(like).callsFake(() => {
return Promise.reject('');
});
stubtwo.withArgs(dislike).callsFake(() => {
return Promise.reject('');
});
likeDislikeService.saveLike(like).then(response => {
console.log('2 -> ');
console.log(response);
assert.lengthOf(response, 1);
}).then((err) => {
console.log(err);
assert.isDefined(err);
});
});
});
describe('findLikeByPostIdAndUserId()', function () {
it('should find likes by post id and user id', function () {
likeDislikeService.findLikeByPostIdAndUserId(1,2).then(response => {
assert.length(response, 1);
});
likeDislikeService.findLikeByPostIdAndUserId(1,2).then(response => {
assert.length(response, 1);
}).catch((err) => {
//console.log(err);
assert.isDefined(err);
});
})
});
describe('findDislikeByPostIdAndUserId()', function () {
it('should find dislikes by post id and user id', function () {
likeDislikeService.findDislikeByPostIdAndUserId(1,2).then(response => {
assert.length(response, 1);
});
likeDislikeService.findDislikeByPostIdAndUserId(1,2).then(response => {
assert.length(response, 1);
}).catch((err) => {
console.log(err);
assert.isDefined(err);
});
})
});
Problem is, I am not getting the "reject" part of the find-methods in the coverage. Also, the saveLike method is not being covered properly apart from the 'then' lines.

nodejs mssql transaction pool

I have a typescript module.
public multipleQuery(queries: string[]) {
return new Promise(async (resolve, reject) => {
const cPool = new sql.ConnectionPool(this.room.db);
await cPool.connect().then((pool: any) => {
const transaction = new sql.Transaction(pool);
return transaction.begin(async (err: any) => {
const request = new sql.Request(transaction, { stream: true });
try {
queries.forEach(async (q) => {
await request.query(q);
});
transaction.commit((err2: any) => {
pool.close();
if (err2) {
reject(err2);
} else {
resolve(true);
}
});
} catch (err) {
transaction.rollback(() => {
pool.close();
reject(err);
});
}
});
}).catch((err: Error) => {
cPool.close();
reject(err);
});
});
}
queries variable is an array of string, I put inside a lot of sql insert queries.
No matter what I write in queries, I still receive this error, why?
RequestError: Requests can only be made in the LoggedIn state, not the
SentClientRequest state TransactionError: Can't acquire connection for
the request. There is another request in progress.
the solutions is to use async
const async = require("async");
public multipleQuery(queries: string[]) {
return new Promise((resolve, reject) => {
const pool = new sql.ConnectionPool(this.room.db);
return pool.connect().then((p: any) => {
const transaction = new sql.Transaction(p);
return transaction.begin((err: any) => {
const request = new sql.Request(transaction);
if (err) {
reject(err);
}
return async.eachSeries(queries, async (query: any, callback: any) => {
return request.query(query);
}, async (err2: any) => {
if ( err2 ) {
await transaction.rollback(() => {
pool.close();
reject(err2);
});
} else {
await transaction.commit(() => {
pool.close();
resolve(true);
});
}
});
});
});
});
}

NodeJS Promise then not executed

I need some help. It's my first try with promises.
Here is my code for the promise:
const deleteUniversRefInTarget = (universName, targetName) => {
console.log('Appel de deleteUniversRefInTarget')
const promis = new Promise((resolve, reject) => {
Target.findOneAndUpdate({ univers: universName, name: targetName },
(err, target) => {
console.log('Entrée dans la promesse')
if (err) {
reject(err)
} else {
if (target === null) {
reject(TypeError(`Invalid univers'n name ${universName}`))
} else {
if (target.univers.length === 1) {
resolve('deleteTarget')
} else {
target.univers.splice(target.univers.indexOf(universName), 1)
resolve('dereferencedUnivers')
}
}
}
})
})
return promis
}
I call this promise here :
exports.deleteATarget = (req, res) => {
deleteUniversRefInTarget(req.params.universName, req.params.targetName)
.then((response) => {
console.log('Fin du traitement de la promesse')
if (response === 'deleteTarget') {
Target.findOneAndDelete({ name: req.params.targetName, univers: req.params.universName },
(err, target) => {
if (err) {
res.send(err)
}
res.json({ message: `Target ${target.name} isn't used in any univers, so we deleted it` })
})
} else {
res.json({ message: `Target ${req.params.targetName} no longer used in ${req.params.universName} univers` })
}
})
.catch((error) => {
res.send(error)
})
}
In the console, I can see :
Appel de deleteUniversRefInTarget
But not Fin du traitement de la promesse
So ... do you know what I'm doing bad ?
I'm not sure I understood everything, but here is my new code about this anti-pattern :
```
const deleteTargetOrDerefUniversInTarget = (universName, targetName) => {
const promis = new Promise((resolve, reject) => {
Target.findOne({ name: targetName, univers: universName })
.then((target) => {
if (target === null) {
reject(TypeError(`Invalid univers'n name ${universName} or target's name ${targetName}`))
} else if (target.univers.length === 1) {
resolve({ action: 'deleteTarget', target })
} else {
resolve({ action: 'dereferencedUnivers', target })
}
})
.catch((err) => {
reject(err)
})
})
return promis
}
exports.deleteATarget = (req, res) => {
deleteTargetOrDerefUniversInTarget(req.params.universName, req.params.targetName)
.then((response) => {
if (response.action === 'deleteTarget') {
Target.findOneAndDelete({ name: response.target.name, univers: req.params.universName })
.then((target) => {
res.json({ message: `Target ${target.name} isn't used in any univers, so we deleted it` })
})
.catch((err) => {
res.status(err.status).json(err)
})
} else {
response.target.univers.splice(response.target.univers.indexOf(req.params.universName), 1)
response.target.save()
res.json({ message: `Target ${response.target.name} no longer used in ${req.params.universName} univers` })
}
})
.catch((error) => {
res.send(error)
})
}
```
In this new code, no more exec call.
The first promise just send back an action to perform that the caller manage.
Ok, sounds much better when I transform my mongoose query (findOneAndUpdate) to a promise :
`
const deleteUniversRefInTarget = (universName, targetName) => {
console.log('Appel de deleteUniversRefInTarget')
const promis = new Promise((resolve, reject) => {
Target.findOneAndUpdate({ univers: universName, name: targetName })
.exec()
.then((target) =>{
console.log('Entrée dans la promesse')
if (target === null) {
reject(TypeError(`Invalid univers'n name ${universName}`))
} else {
if (target.univers.length === 1) {
resolve('deleteTarget')
} else {
target.univers.splice(target.univers.indexOf(universName), 1)
resolve('dereferencedUnivers')
}
}
})
.catch((err) => {
reject(err)
})
})
return promis
}
`
And the difference is mainly the .exec() part.
I think we can say it's solve ... even if I'm not sure it's the correct way to do ot.

NodeJS two queries in one route

I need to display Invitation and Comments in the same rendered file (show.hbs)
I have this code here, and it's working fine, except I cannot achieve that comment's would also display. I would really appreciate any help.
I'm not getting any errors with this code.
app.get('/invitation/:id', (req, res) => {
let id = req.params.id;
if(!ObjectID.isValid(id)){
return res.status(404).send();
}
Comment.find({inviteId: id}).then((comment) => {
if(!comment){
return res.status(404).send();
}
res.render('show.hbs', {comment});
}, (e) => {
res.status(404).send();
});
Invitation.findById(id).then((invitation) => {
if(!invitation){
return res.status(404).send();
}
res.render('show.hbs', {invitation});
}, (e) => {
res.status(404).send();
});
}, (e) => {
console.log('Unable to find invitation', e);
});
You can do something like this,
Invitation.findById(id).then((invitation) => {
if (!invitation) {
return res.status(404).send();
}
Comment.find({ inviteId: id }).then((comment) => {
if (!comment) {
return res.status(404).send();
}
res.render('show.hbs', { comment, invitation});
}, (e) => {
res.status(404).send();
});
}, (e) => {
res.status(404).send();
});
and render it with both invitation and comment
Tnx to #vibhor1997a but this is much prettier
try {
let invitation = await Invitation.findById(id).then((invitation) => {
if (!invitation) {
return res.status(404).send();
}
let comments = await Comment.find({ inviteId: id })
if (!comments) {
return res.status(404).send();
}
return res.render('show.hbs', { comments, invitation});
} catch (e) {
return res.status(500).send();
}
You didn't paste your error message, but I'm pretty sure it's something like Error: Can't set headers after they are sent to the client.
Just nest your queries or use await https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await.

Resources