Sqlite transactions in nodejs - node.js

Accordingly with nodejs sqlite library (https://github.com/mapbox/node-sqlite3) you can serialize a sql transaction with db.serialize function. All executions in this function will be executed in the specified order.
But with a for loop how can i get the information about the transaction will be success or fail?
function transaction(callback) {
db.serialize(function() {
db.run("BEGIN");
for(...) {
db.run("INSERT", function(err) {
//this code is not serialized with the parent serialize function (this is my problem)
//if one run throw error i must resolve the callback with the error code
if (err)
callback("error");
});
}
db.run("END");
callback("ok");
}
}

Before start transaction you can define some vars e.g. var results = [];. On complete each query inside callback you can collect error or null as results.push(err) and check results.length. When results.length equals to length of for then all queries executed and now check results.every((i) => i === null) value. If true then do commit else rollback.
Much better to control flow is use async module.
'use strict'
var async = require('async');
...
db.run('begin', function(err){
if (err)
return console.log(err);
let run = (sql, callback) => db.run(sql, callback);
async.eachSeries(sqls, run, function(err){
db.run((err) ? 'rollback' : 'commit', ...)
})
})
If you add begin to sqls then code will be more simple.

Related

AWS Lambda query with async waterfall in node.js 8.10

I send two query sequentially
Query the data from A tables, and then accoring to the result, query the data from B table.
So, I query the data like that,
var async = require('async');
var mysql = require('mysql');
var config = require('./config.json');
var connection = mysql.createConnection({
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
exports.handler = (event, context, callback) => {
// TODO implement
var tasks = [
function (callback) {
connection.query("SELECT email FROM Visitor WHERE id =?;", [1], function (err, row) {
if (err) return callback(err);
if (row.length == 0) return callback('No Result Error');
callback(null, row[0]);
})
},
function (data, callback) {
connection.query("SELECT id,signtime FROM Board WHERE email =?;", data.email, function (err, row) {
if (err) return callback(err);
if (row.length == 0) {
return callback('No Result Error');
}else {
callback(null, row[0])
}
})
}
];
async.waterfall(tasks, function (err, result) {
if (err)
console.log('err');
else
***return result;***
console.log('done');
connection.end();
});
};
I log the data with console.log(), it take the data in command line.
But in lambda, put the function into exports.handler, it response null.
If I change the 'return result' to callback(result), it occurs error.
I think it maybe too simple to solve this problem
If you know about that, please help me
In the first case, response is null because you didn't use neither Promise, nor callback to let the Lambda sandbox know that the job is done. In the second case, you used the callback, but you passed the result as the first argument to it. Lambda programming model for Node.js follows a principle called "error first callback". Long story short, if any error occurred during execution, you should go with callback(error), and if everything is ok and you need to return some result from lambda, you should go with callback(null, result). So basically on your line before console.log('done'); use callback(null, result) and it will work for you.

Variable is null after returned from lambda function in AWS

I tried to define local variable then call lambda function which populates the value to my local variable:
var listOfAliases = null;
lambda.invoke(params, function(err, data) {
if (err) {
//context.fail(err);
console.log(`This is the ERROR execution =${err} =================================`);
prompt(err);
} else {
//context.succeed('Data loaded from DB: '+ data.Payload);
listOfAliases = JSON.stringify(data.Payload);
console.log(`This is the VALIDE execution =${data.Payload} =================================`); //I can see this in the log with proper values
console.log(`This is the VALIDE execution(listOfAliases) =${listOfAliases} =================================`); //I can see this in the log with proper values
}
callback(null, JSON.parse(data.Payload));
});
console.log(`This is the DB execution listOfAliases=${listOfAliases} =================================`); //I can see this in the log with NULL value
The problem here is that lambda.invoke executes asynchronously and your last console.log executes before the invoke callback function completes.
If you need to access the result from outside one the asynchronous call completes, you could use a promise.
var promise = new Promise(function(resolve,reject){
lambda.invoke(params, function(err, data) {
if (err) {
reject(err);
} else {
resolve(JSON.stringify(data.Payload));
}
});
});
promise.then(function(listOfAliases){
console.log('This is the DB execution listOfAliases ' + listOfAliases);
});

node-postgres : query not executing in sequence

i have kept insert & update code in 2 different files and based on condition
always insert should execute first and then update.but somehow update executes first then insert
test.js : simplified code
i am using these packages :pg , uuid
var pg = require('pg');
var uuid = require('node-uuid').v4;
var id = uuid().toString();
var conString = 'postgres://postgres:pass#127.0.0.1:5432/testdb';
// ------INSERT
pg.connect(conString, function(err, client, done) {
console.log('Executing Insert query');
client.query('insert into testdb (id,data,iscancelled) values ($1,$2,$3)',[id,'hello','no'], function(err, result) {
done();
if(err) { return console.error('error running query', err); }
console.log('finished executing Insert query');
});
});
// ------UPDATE
pg.connect(conString, function(err, client, done) {
console.log('Executing update query');
client.query("update testdb set iscancelled = 'yes' where id = $1",[id], function(err, result) {
done();
if(err) { return console.error('error running query', err); }
console.log('finished executing Update query');
});
});
output
tom#tom:~$node test.js
Executing Insert query
Executing update query
finished executing Update query //WHY UPDATE FINISHES FIRST
finished executing Insert query
Note :
this problem can be easily solved by using async.But my insert code and update code are in different files and depending on some situation update code might execute.so don't want to use async
Problem
Even though Insert query goes to execute first why does update finishes first in output
am i missing any thing ..?
Lets solve this question step by step
you "stated so don't want to use async" libraries
solution 1 :
if PostgreSQL make update faster, update will return result before insert. If you want start executing update query only after finishing insert then
you should set connection pool capacity to 1.
pg.defaults.poolSize = 1
but you should do this before any pg.connect()
The connect method retrieves a Client from the client pool, or if all pooled clients are busy and the pool is not full, the connect method will create a new client passing its first argument directly to the Client constructor. In either case, your supplied callback will only be called when the Client is ready to issue queries or an error is encountered. The callback will be called once and only once for each invocation of connect.
Conclusion : your queries will execute in sequence.BUT BUT BUT this solution is BAD for scaling app as there will be always only one connection serving all users .So till one connection is serving one user , other users will have to wait for response.
Solution 2 :
you also stated "i have kept insert & update code in 2 different files"
it looks like you need to designed your code in such a way that it you are able to use asynchronus libraries , that solves this problem
As I already mentioned, the only way to ensure that update function will be fired only after insert function is done, is to call it inside of insert function callback. That are the basics of asynchronous programming.
pg.connect(conString, function(err, client, done) {
console.log('Executing Insert query');
client.query('insert into testdb (id,data,iscancelled) values ($1,$2,$3)',[id,'hello','no'], function(err, result) {
done();
if(err) { return console.error('error running query', err); }
console.log('finished executing Insert query');
// ------UPDATE
pg.connect(conString, function(err, client, done) {
console.log('Executing update query');
client.query("update testdb set iscancelled = 'yes' where id = $1",[id], function(err, result) {
done();
if(err) { return console.error('error running query', err); }
console.log('finished executing Update query');
});
});
});
You are missing the asynchronous nature of the pg.connect and also client.query. The call to these return a callback which passes the control to next expression before the completion of execution and hence non-blocking nature of nodejs. If you want to assure the correct flow, either call the successive ones inside the callback success
var pg = require('pg');
var uuid = require('node-uuid').v4;
var id = uuid().toString();
// ------INSERT
return pg.connect;
// ------UPDATE
return pg.connect;
// your calling file
var insert = require('/path/to/insertfile');
var conString = 'postgres://postgres:pass#127.0.0.1:5432/testdb';
var update = require('/path/to/updatefile');
insert(conString, function (err, client, done) {
console.log('Executing Insert query');
client.query('insert into testdb (id,data,iscancelled) values ($1,$2,$3)',[id,'hello','no'], function (err, result) {
if (err) {
return console.error('error running query', err);
}
console.log('finished executing Insert query');
update(conString, function (error, client, done) {
console.log('Executing update query');
client.query("update testdb set iscancelled = 'yes' where id = $1",[id], function (err, result) {
if (err) {
return console.error('error running query', err);
}
console.log('finished executing Update query');
done();
});
});
done();
});
});
But this is very prone to callback hell. So consider making all async call return a promise. Take a look at bluebird. If you want an ORM that has built in promise based call, you can take a look at sequelize. It might be handy for you.
It has syntax as easy as:
var Model1 = require('/path/to/model1');
var Model2 = require('/path/to/model2');
var insertObj = {
"someKey": "value"
};
Model1.create(insertObj)
.then( function (createdObj1) {
return Model2.findOne({
where: {
"filter": "filterValue"
}
});
})
.then( function (documentToUpdate) {
return documentToUpdate.update({
"fieldToUpdate": "value"
});
})
.then( null, function (err) {
console.log(err);
});

Process.nextTick or child_process?

I am trying to allow users to export their contact list in csv format. I am confused on how to run export_connect_csv() function. should i put it in child process or process.nextTick?
function export_connect_csv(user_id, file_location){
mysqlPool.getConnection(function(err, connection){
var csv_row = "Email,First Name,Last Name,Status,Created\n";
function processRow (row) {
var csv_row = row.email+','+row.first_name+','+row.last_name+','+row.status+','+row.created+"\n";
fs.appendFile(file_location, csv_row, function (err) {
if(err){
throw err;
}
});
}
fs.appendFile(file_location, csv_row, function (err) {
if(err){
throw err;
}
var query = connection.query('SELECT * FROM contacts where user_id = "'+user_id+'"');
query
.on('error', function(err) {
//handle error
})
.on('fields', function(fields) {
})
.on('result', function(row) {
processRow(row);
})
.on('end', function() {
//email now
console.log('done');
});
});
});
}
var exportContacts = function(req, res){
var user_id = req.params.user_id || 0;
export_connect_csv(user_id);
res.json({});
};
You don't need to use either, you can just call the function. All of that code will run assynchronously, both getConnection and fs.appendFile. However, you will run into a conflict in the case two users try to export at the same time. You have the following options:
1) You pass a unique file_name every time you call that function
2) You keep things exactly as they are and use fs.appendFileSync to make sure they don't overlap each other but that would block you
3) Or probably the best solution is do what you intended to do with the Process.nextTick, but instead you should use setImmediate and appendFileSync to be able to synchronize writes from several users simultaneously (write only a row at a time to avoid blocking for long periods):
setImmediate(function () {
fs.appendFileSync('filename', JUST_A_SINGLE_ROWW)
});
This is because a recursive process.nextTick can starve the event loop and effecively block you (hence the use of setImmediate) and you need to use fs.appendFileSync because two users might write to the same file simultaneously.
More on setImmediate vs nextTick:
setImmediate vs. nextTick
More info on appendFile: http://nodejs.org/api/fs.html#fs_fs_appendfile_filename_data_options_callback

function not worked synchronously in nodejs?

I am little bit confused with my code it's not worked synchronusly as it's should be. I use everyauth to do authentication.
registerUser(function(newUserAttrs) {
var login = newUserAttrs[this.loginKey()];
user.CreateNewUser(newUserAttrs.login, newUserAttrs.password, newUserAttrs.email, function(res, err) {
if(!err) {
return usersByLogin[login] = newUserAttrs;
}
else {
throw err;
}
});
})
in another file I have write this code
exports.CreateNewUser = function(login, pass, mail, callback) {
var sql = "insert into `user`(login,mail,pass) values(?,?,?)";
client.query(sql, [login, mail, pass], function(err, results, fields) {
if(!err) {
callback(results);
console.log('test')
}
else {
callback(results, err);
}
});
};
This code are working fine. I have tested him. the only problem is they are working synchronosly (as normal). Can someone explain me what thing I have done in wrong way that make it async. I want to get it done in sync way.
The current code give me error (it's make a entry in database and produce error on browser)
Error: Step registerUser of `password` is promising: userOrErrors ; however, the step returns nothing. Fix the step by returning the expected values OR by returning a Promise that promises said values.
at Object.exec (E:\proj\Node\node_modules\everyauth\lib\step.js:68:11)
at E:\proj\Node\node_modules\everyauth\lib\stepSequence.js:26:38
at [object Object].callback (E:\proj\Node\node_modules\everyauth\lib\promise.js:13:12)
at RouteTriggeredSequence._bind (E:\proj\Node\node_modules\everyauth\lib\stepSequence.js:25:20)
at RouteTriggeredSequence.start (E:\proj\Node\node_modules\everyauth\lib\stepSequence.js:52:33)
at RouteTriggeredSequence.routeHandler (E:\proj\Node\node_modules\everyauth\lib\routeTriggeredSequence.js:13:13)
at Object.<anonymous> (native)
at nextMiddleware (E:\proj\Node\node_modules\connect\lib\middleware\router.js:175:25)
at param (E:\proj\Node\node_modules\connect\lib\middleware\router.js:183:16)
at pass (E:\proj\Node\node_modules\connect\lib\middleware\router.js:191:10)
Thanks
The two pieces of code you present are asynchronous and not synchronous!
With everyauth, to be able to handle asynchronous user creation you should use a Promise. So your code will be something like :
registerUser(function(newUserAttrs) {
var promise = this.Promise();
var login = newUserAttrs[this.loginKey()];
user.CreateNewUser(newUserAttrs.login, newUserAttrs.password, newUserAttrs.email, function(res, err) {
if(!err) {
return promise.fulfill(newUserAttrs);
}
else {
promise.fulfill(user);
}
});
})
Without promise you couldn't be sure that your new user has been added in your database. But if it doesn't matter you could have something like that:
registerUser(function(newUserAttrs) {
var login = newUserAttrs[this.loginKey()];
user.CreateNewUser(newUserAttrs.login, newUserAttrs.password, newUserAttrs.email, function(res, err) {
if (err) console.log(err);
});
return newUserAttrs;
})
Because you are doing a database query, this code has to be asynchronous. The anonymous function you pass to client.query will not be called until the database query is complete, so your callback gets called asynchronously.
You will need to treat this all as asynchronous, so for instance you'll have to trigger some other callback instead of returning the user object/throwing.

Resources