SQLError 19 UNIQUE constraint failed - javascript

I am getting this error when setting up my app, creating a local database and simply inserting the first and only user (who has logged in locally). Please see comment in code for where I get the error message.
angular.module("greenApp")
.service("dbService",['$q', function($q){
var db;
var promise = function(){
var deferred = $q.defer();
db = window.openDatabase('greenDB', '1.0', 'Green Database', 2*1024*1024);
db.transaction(function(tx){
tx.executeSql("CREATE TABLE IF NOT EXISTS user (user TEXT PRIMARY KEY) ")
}, function(err){
alert('Something went wrong... Error: DATABASE INIT ' + err);
}, function(scc){
deferred.resolve();
})
return deferred.promise;
}
promise();
var query = function(sql, args) {
var deferred = $q.defer();
db.transaction(function(tx) {
tx.executeSql(sql, args, function(tx, results) {
deferred.resolve(results);
});
}, function(err) {
deferred.reject(err);
});
return deferred.promise;
};
var insert_into = function(args) {
var queryPromise = query("INSERT INTO user (user) VALUES (?)", args);
console.log("in insert_into", queryPromise) // Error message comes here
return queryPromise;
};
return {
promise: promise,
insert_into: insert_into,
};
}]);
Where args is simply ["user-name-string"], I get an error message that says:
"could not execute statement due to a constaint failure (19 UNIQUE
constraint failed: user.user)
Any ideas what could have happened? Exactly the same code was running and working in a recent pure cordova project which I just ported to Ionic.

It looks like you are inserting twice in your code ... here
var insert_into = function(args) {
var queryPromise = query("INSERT INTO user (user) VALUES (?)", args);
console.log("in insert_into", queryPromise) // Error message comes here
return query("INSERT INTO user (user) VALUES (?)", args); <-- you did a query above, now you do it again?!?
};

The sqlite db persists when you exit the app, so each time you start the app it will try to do the insert. (I gess it worked at first launch and you got the error the second time).
As you use CREATE TABLE IF NOT EXISTS the app does not fail on table creation but on the first insert.
You can use the pragma user_version to read/write version of your database and so know in wich case you have to create tables / insert values or if the db is already ready to go.

Related

In Node, how to execute sql from global database connection

I am unable to execute the sql, when using the global database connection in node.js.
I have followed the steps as in Azure documentation: https://learn.microsoft.com/en-us/azure/mysql/connect-nodejs and able to display the output on the console. But, I want to put all my Azure SQL database connection in a separate file, but the select query is not printing the output on the console.
DatabaseManager.js
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var sqlConnection = function sqlConnection() {
// Create connection to database
var config =
{
userName: 'uname',
password: 'password',
server: 'dbserver.database.windows.net',
options:
{
database: 'mydatabase',
encrypt: true
}
}
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err)
{
console.log(err)
}
else
{
console.log('CONNECTED TO DATABASE');
}
}
);
}
module.exports = sqlConnection;
app.js
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require("botbuilder-azure");
var azure = require('azure-storage');
var dbconnection = require('./DatabaseManager');
bot.dialog('profileDialog',
(session) => {
session.send('You reached the profile intent. You said \'%s\'.', session.message.text);
console.log('Reading rows from the Table...');
dbconnection("select FNAME from StudentProfile where ID=1"),
function (err, result, fields) {
if (err) throw err;
console.log(result);
}
session.endDialog();
}
Console Output:
Reading rows from the Table...
CONNECTED TO DATABASE
I was expecting the output of FNAME, but nothing is printing on the console. Is there anything, I am missing?
Thank you.
There's a couple of problems here. First off, you should only ever import a module once per file. This is just a performance consideration and won't actually break your code.
Next, pay attention to what you're exporting from your DatabaseManager module. Right now, you're exporting a function that creates the connection and then doesn't do anything with it. We can fix this by using a pattern called a "callback" which lets us provide a function that will then be called with the connection as an argument.
I added a ton of comments to the code explaining things. This code won't run as-is - there's a couple places where I have "do this or this". You'll have to choose one.
var Tedious = require('tedious'); // Only require a library once per file
var Connection = Tedious.Connection;
var Request = Tedious.Request;
// Or using the object spread operator
var { Connection, Request } = require('tedious');
// You called this `sqlConnection`. I'm going to use a verb since it's a
// function and not a variable containing the connection. I'm also going
// to change the declaration syntax to be clearer.
function connect(cb) { // cb is short for callback. It should be a function.
var config = {
userName: 'uname',
password: 'password',
server: 'dbserver.database.windows.net',
options: {
database: 'mydatabase',
encrypt: true
}
}; // Put a semi-colon on your variable assignments
var connection = new Connection(config);
// Attempt to connect and execute queries if connection goes through
connection.on('connect', function(err) {
if (err) {
console.log(err);
return; // Stop executing the function if it failed
}
// We don't need an "else" because of the return statement above
console.log('CONNECTED TO DATABASE');
// We have a connection, now let's do something with it. Call the
// callback and pass it the connection.
cb(connection);
});
}
module.exports = connect; // This exports a function that creates the connection
Then back in your main file, you can use it like so.
var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require('botbuilder-azure');
var azure = require('azure-storage');
var connect = require('./DatabaseManager'); // renamed to be a verb since it's a function.
bot.dialog('profileDialog', (session) => { // Hey, this is a callback too!
session.send('You reached the profile intent. You said \'%s\'.', session.message.text);
console.log('Creating a connection');
connect((connection) => {
// or with the traditional function notation
connect(function(connection) {
console.log('Reading rows from the Table...');
// Execute your queries here using your connection. This code is
// taken from
// https://github.com/tediousjs/tedious/blob/master/examples/minimal.js
request = new Request("select FNAME from StudentProfile where ID=1", function(err, rowCount) { // Look another callback!
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
});
request.on('row', function(columns) { // Iterate through the rows using a callback
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log(column.value);
}
});
});
connection.execSql(request);
});

Azure Node: Access table storage from SQL Azure Easy tables insert function

I'm trying to insert some data into table storage from the SQL Azure EasyTables insert statement but context.execute() is being called before the table is created in table storage which stops my connection even though the code to create a new table is placed before context.execute(). Could some one tell me how I could stall the context.execute function until I finish my table storage set up. Below is my code. Thanks for the help
table.insert(function (context) {
var azure = require('azure-storage');
var tableService = azure.createTableService('NAME', 'KEY');
context.user.getIdentity().then((data) => {
tableService.createTableIfNotExists('UserInfo', function(error, result) {
if (error) {
//do something
}else {
var entGen = azure.TableUtilities.entityGenerator;
var task = {
PartitionKey: entGen.String(context.user.id),
RowKey: entGen.String('1'),
name : entGen.String(data.facebook.claims.name),
email : entGen.String(data.facebook.claims.emailaddress),
createdOn: entGen.DateTime(new Date(Date.UTC(2016, 3, 27))),
};
tableService.insertEntity('UserInfo',task, function (error, result, resp) {
if(!error){
//respond with success message
}else{
//respond with failure message
}
});
}
});
});
context.item.userId = context.user.id;
return context.execute(); //This line is executed before I get success/failure response from table storage
});
This is because getIdentity() returns a Promise object.
The code then((data) => { ... }) will be executed after its being invoked successfully.
More details about how Promise.then() works, pls see here
You can write the code tableService.createTableIfNotExists(...); into a method and call the method in context.execute().
I wrote the tableService.createTableIfNotExists(...); into a new function and then called the function from "use" operation
table.insert.use(insertMiddleware, table.operation);

Node.js: Undefined return value after database query

I got a file newuser.js (node.js environment featuring a mongodb database managed via mongoose) containing the following code:
//newuser.js
//basically creates new user documents in the database and takes a GET parameter and an externally generated random code (see randomcode.js)
[...]
var randomCode = require ('randomcode');
var newTempUser = new tempUser({name: req.body.name, vericode: randomCode.randomveriCode(parameter)
});
newTempUser.save(function (err){
//some output
});
//randomcode.js
//creates a random sequence of characters (=vericode), checks if code already exists in DB and restarts function if so or returns generated code
exports.randomveriCode = function randomveriCode(parameter){
[...]
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter){
if (counter=='0'){
return generatedcode;
}else{
randomveriCode(parameter);
}
});
};
Problem is, that newuser.js throws an error as variable vericode is 'undefined' (thus mongoose model validations fails). The error does not occur if I skip the database query and instantly return the generated code (which in fact has got a value as verified by several console.log instructions). It occurs to me that the db query takes to long and empty or null value returned before query is complete? I thought about introducing promises unless you got any other suggestions or hints what may cause this behaviour?
Kind regards
Igor
Since querying the database is a non-blocking operation, you cannot expect the function call to return the value from the database immediately. Try passing in a callback instead:
// newuser.js
var randomCode = require('randomcode');
randomCode.randomveriCode(parameter, function(err, code) {
if (err) throw err; // TODO: handle better
var newTempUser = new tempUser({name: req.body.name, vericode: code});
newTempUser.save(function (err){
//some output
});
});
// randomcode.js
exports.randomveriCode = function randomveriCode(parameter, cb) {
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter) {
if (err) return cb(err);
if (counter == '0') {
cb(null, generatedcode);
} else {
randomveriCode(parameter, cb);
}
});
};
your randomveriCode function contains calls to an asynchronous function and therefore, your function really needs to provide a callback argument like this:
exports.randomveriCode = function randomveriCode(parameter, callback){
[...]
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter){
if(err) return callback(err);
if (counter=='0'){
return callback(null, generatedcode);
}else{
randomveriCode(parameter, callback);
}
});
};
You'd then call it like so:
var randomCode = require ('randomcode');
randomCode(function(err, vericode){
if(err) throw err;
var newTempUser = new tempUser({name: req.body.name, vericode: vericode});
newTempUser.save(function(err,newUser){
//do something here
});
});
Btw - you could also use a synchronous function to create a GUID. See https://www.npmjs.org/package/node-uuid.

Promised Connections Returning Nothing (JS)

Problem with Promised Connections
I recently converted my Node app from running on my local machine to utilizing an Amazon EC2 for the Node app and a VPN for the file-serving and MySQL.
I learned just enough about Promises to write the following connection snippet (which runs 3 queries before responding to the client), utilizing Bluebird. The connections worked on my machine, but with the VPN hosted MySQL settings, the connections crashed every time, about 30 seconds after the app started, which I realized was probably because I'd forgotten to close them.
EDIT: Based on the comments, it appears the issue is not in the connection closures.
So I modified my script in the best way I knew to close the connections, but with Promises, this is confusing. This version of the connection doesn't work. It doesn't fail or cause any errors. It just returns no results on the server side. I think my problem is in the way I've closed the connections.
What's causing the issue?
Is it the connection closures?
If so, how would I close them properly?
My (Simplified) MySQL Connection Attempt with Bluebird Promises
var mysql = require('mysql');
var Promise = require('bluebird');
var moment = require('moment');
function createConnection() {
var connection = mysql.createConnection({
dateStrings : true,
host : 'hostname',
user : 'username',
password : 'password',
database : 'database'
});
connection = Promise.promisifyAll(connection);
return connection;
}
function sendGame(req, res, sales, settings, categories, players) {
var game = new Object();
game.sales = sales;
game.players = players;
game.settings = settings;
game.categories = categories;
var JSONgame = JSON.stringify(game);
console.log("Game: " + JSON.stringify(game, undefined, 4));
}
var retrieveSales = Promise.method(function (username, connection, timeFrame) {
console.log('User ' + username + ' retrieving sales...');
var q = 'select * from sales_entries where date BETWEEN ? AND ?';
return connection.queryAsync(q, timeFrame).then(function (results) {
return results[0];
});
});
var retrieveSettings = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving settings...');
var q = 'select * from sales_settings';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var retrieveCategories = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving categories...');
var q = 'select * from sales_categories';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var retrievePlayers = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving players...');
var q = 'select * from users';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var gameSucceed = Promise.method(function gameSucceed(req, res) {
var username = req.body.username;
console.log('User ' + req.body.username + ' retrieving game...');
var timeFrame = [moment().days(0).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss"), moment().days(6).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss")];
//var connection = Promise.promisifyAll(createConnection());
return connection.connectAsync().then(function () {
console.log('Connection with the MySQL database openned for Game retrieval...');
return Promise.all([retrieveSales(username, connection, timeFrame), retrieveSettings(username, connection), retrieveCategories(username, connection), retrievePlayers(username, connection)]);
}).then(function () {
connection.end(),
console.log("...Connection with the MySQL database for Game retrieval ended")
});
});
function getGameData(req, res) {
gameSucceed(req, res).spread(function (sales, settings, categories, players) {
return sendGame(req, res, sales, settings, categories, players);
});
};
var req = new Object();
var res = new Object();
req.body = {
"username" : "user123",
"password" : "password"
}
getGameData(req, res);
Console Result
User user123 retrieving game...
Connection with the MySQL database openned for Game retrieval...
User user123 retrieving sales...
User user123 retrieving settings...
User user123 retrieving categories...
User user123 retrieving players...
...Connection with the MySQL database for Game retrieval ended
Game: {}
var gameSucceed = function gameSucceed(req, res) {
…
var connection = createConnection());
return connection.connectAsync().then(function () {
return Promise.all([…]);
}).then(function () {
connection.end();
});
};
The promise that is ultimately returned from this method does not have a resolution value. It is created by that then call from whose callback you do not return - which will lead to undefined. To fix this, just route the result through:
.then(function(results) {
connection.end();
return results;
});
However, if you do it like that the connection won't be closed in case of an error. The best solution is to use the finally() method, which just works like a finally clause in synchronous code. It's callback will be invoked both for resolutions and rejections, and the resulting promise will automatically carry on the value.
.finally(function() {
connection.end();
})
// .then(function(results) { })
Your code has a particular resource management problem like Bergi put it. You have to keep remembering when to close the collection and when not to.
The optimal solution would be to use Promise.using however, that's only available in the v2 branch of Bluebird so you're going to have to wait a while.
Until then, you can create your own wrapper method that does more basic scoped resource management:
function connect(fn,timeout){
timeout = (timeout === undefined) ? 8000 : timeout; // connection timeout
return createConnection().then(function(connection){
// run the function, when it resolves - close the connection
// set a 7 second timeout on the connection
return fn(connection).timeout(timeout).finally(function(){
connection.end();
});
});
}
Which would let you do:
connect(function(connection){
return gameSucceed(req,resp,connection); // connection is injected to that fn now
}).then(function(val){
// gameSucceed resolution value here
});
Now, when the gameSucceed is done, the connection will close itself automatically. This would make gameSucceed itself look like:
var gameSucceed = Promise.method(function gameSucceed(req, res,connection) {
var username = req.body.username;
console.log('User ' + req.body.username + ' retrieving game...');
var timeFrame = [moment().days(0).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss"), moment().days(6).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss")];
return connection.connectAsync().then(function () {
console.log('Connection with the MySQL database openned for Game retrieval...');
return Promise.all([retrieveSales(username, connection, timeFrame), retrieveSettings(username, connection), retrieveCategories(username, connection), retrievePlayers(username, connection)]);
}); // no longer its responsibility to handle the connection
});
Generally, you might also want to consider a more OOPish style of coding for your code.
Good luck, and happy coding.

Node.JS EventEmitter Listener Must be a Function

I am getting an error when attempting to setup listeners within a function. I have reviewed other code that this works for, but can't seem to get it to work for my purposes.
This is a simplified version of what I am attempting to get done.
var ticketGenerator = function(){
var self = this;
console.log('ticket generator');
var rows = "";
this.emit("getQueue")
var _getQueue = function(){
console.log('Getting Queue');
var connection = mysql.createConnection({
//Connection Data
});
connection.connect();
connection.query("SELECT * FROM `queue` WHERE `run` = 0 ORDER BY `queueID` ASC LIMIT 1", function(err, rows, fields){
if(err){
//self.emit("error", "Unable to get data from the database.")
console.log(err);
}
else if(typeof rows[0] == "undefined"){
console.log("Waiting to run again.");
connection.end();
setTimeout(function(){ticketGenerator()}, 60000);
}
else{
console.log("Passing Ticket Data");
self.emit("newTicketData", rows);
connection.end();
}
})
};
this.on("getQueue", _getQueue);
}
I cannot get it to run the function for _getQueue. When I put in the listener _getQueue() it will run the function, but throws an error (TypeError: listener must be a function). I'm not sure what I am doing wrong as I have seen other code written in this way that is working.
I have verified that I have the listeners setup with this.on('newListener' . . . ). I assume that since I can get it to call the function when changing the name on the listener that the emitter is doing it's job as well.
Note that this ticketGenerator function is being called from another file using requires. I don't know if this will affect the solution for this issue, but figured that detail may be important.
---------------EDIT----------------
I ended up figuring this out after I posted this. I needed to call a constructor for these events to go through. The code looks like the following.
events.EventEmitter.call(this);
I couldn't answer my own question due to rep, but will update the answer area when I can.
Here's a solution to different of your problems:
In your sample, self will be associated with the window or global namespace. There's no way you can access your EventEmitter using this.
You emit the first getQueue event before attaching a listener. You must instantiate your TicketGenerator and then emit the first getQueue to get the wheel started.
In your timeout, just need to emit a new getQueue to retry, no need to instantiate the TicketGenerator again.
Hope this helps.
TicketGenerator = function() {
var self = this;
console.log('ticket generator');
var rows = "";
EventEmitter.call(this);
var _getQueue = function() {
console.log('Getting Queue');
var connection = mysql.createConnection({
//Connection Data
});
connection.connect();
connection.query("SELECT * FROM `queue` WHERE `run` = 0 ORDER BY `queueID` ASC LIMIT 1", function(err, rows, fields){
if(err){
//self.emit("error", "Unable to get data from the database.")
console.log(err);
}
else if(typeof rows[0] == "undefined"){
console.log("Waiting to run again.");
connection.end();
setTimeout(function(){
self.emit('getQueue');
}, 60000);
}
else {
console.log("Passing Ticket Data");
self.emit("newTicketData", rows);
connection.end();
}
});
}
this.on("getQueue", _getQueue);
};
// Instantiate the ticket generator and initiate the first queue retrieval
var ticketGenerator = new TicketGenerator();
ticketGenerator.emit('getQueue');

Categories

Resources