JavaScript control flow in node/redis: returning from inside callback? - javascript

Newbie question. Why is this JavaScript function returning undefined?
var redis = require("redis"), client = redis.createClient();
function generatePageUrl() {
var randomStr = randomInt.toString(32);
// Check whether this URL is already in our database;
client.smembers("url:" + randomStr, function (err, data ) {
if (data.length != 0) {
// URL already in use, try again
return getPageUrl();
}
return randomStr;
});
}
var page_url = generatePageUrl();
// add it to the database, etc
I guess it must be getting to the end and returning before it reaches the inside of client.smembers.
But I really need to check the contents of the Redis set before it returns: can I get it to return from inside the callback? If not, what can I do?
Also, advice on the way I've used this function recursively would be welcome - I'm not sure it's completely sensible :)
Thanks for helping out a newcomer.

You can't return from inside a callback. Do it like this:
var redis = require("redis"), client = redis.createClient();
function generatePageUrl(cb) {
var randomStr = randomInt.toString(32);
// Check whether this URL is already in our database;
client.smembers("url:" + randomStr, function (err, data ) {
if (data.length != 0) {
// URL already in use, try again
getPageUrl(cb);
}
cb(randomStr);
});
}
generatePageUrl(function(page_url){
// add it to the database, etc
});
If you don't like this style, you might want to consider streamlinejs - it makes you able to write your code like this:
var redis = require("redis"), client = redis.createClient();
function generatePageUrl(_) {
var randomStr = randomInt.toString(32);
// Check whether this URL is already in our database;
var data = client.smembers("url:" + randomStr, _);
if (data.length != 0) {
// URL already in use, try again
return getPageUrl(_);
}
return randomStr;
}
var page_url = generatePageUrl(_);
// add it to the database, etc

Related

Get specifics ids in IndexedDB [duplicate]

I want to execute this query
select * from properties where propertyCode IN ("field1", "field2", "field3")
How can I achieve this in IndexedDB
I tried this thing
getData : function (indexName, params, objectStoreName) {
var defer = $q.defer(),
db, transaction, index, cursorRequest, request, objectStore, resultSet, dataList = [];
request = indexedDB.open('test');
request.onsuccess = function (event) {
db = request.result;
transaction = db.transaction(objectStoreName);
objectStore = transaction.objectStore(objectStoreName);
index = objectStore.index(indexName);
cursorRequest = index.openCursor(IDBKeyRange.only(params));
cursorRequest.onsuccess = function () {
resultSet = cursorRequest.result;
if(resultSet){
dataList.push(resultSet.value);
resultSet.continue();
}
else{
console.log(dataList);
defer.resolve(dataList);
}
};
cursorRequest.onerror = function (event) {
console.log('Error while opening cursor');
}
}
request.onerror = function (event) {
console.log('Not able to get access to DB in executeQuery');
}
return defer.promise;
But didn't worked. I tried google but couldn't find exact answer.
If you consider that IN is essentially equivalent to field1 == propertyCode OR field2 == propertyCode, then you could say that IN is just another way of using OR.
IndexedDB cannot do OR (unions) from a single request.
Generally, your only recourse is to do separate requests, then merge them in memory. Generally, this will not have great performance. If you are dealing with a lot of objects, you might want to consider giving up altogether on this approach and thinking of how to avoid such an approach.
Another approach is to iterate over all objects in memory, and then filter those that don't meet your conditions. Again, terrible performance.
Here is a gimmicky hack that might give you decent performance, but it requires some extra work and a tiny bit of storage overhead:
Store an extra field in your objects. For example, plan to use a property named hasPropertyCodeX.
Whenever any of the 3 properties are true (has the right code), set the field (as in, just make it a property of the object, its value is irrelevant).
When none of the 3 properties are true, delete the property from the object.
Whenever the object is modified, update the derived property (set or unset it as appropriate).
Create an index on this derived property in indexedDB.
Open a cursor over the index. Only objects with a property present will appear in the cursor results.
Example for 3rd approach
var request = indexedDB.open(...);
request.onupgradeneeded = upgrade;
function upgrade(event) {
var db = event.target.result;
var store = db.createObjectStore('store', ...);
// Create another index for the special property
var index = store.createIndex('hasPropCodeX', 'hasPropCodeX');
}
function putThing(db, thing) {
// Before storing the thing, secretly update the hasPropCodeX value
// which is derived from the thing's other properties
if(thing.field1 === 'propCode' || thing.field2 === 'propCode' ||
thing.field3 === 'propCode') {
thing.hasPropCodeX = 1;
} else {
delete thing.hasPropCodeX;
}
var tx = db.transaction('store', 'readwrite');
var store = tx.objectStore('store');
store.put(thing);
}
function getThingsWherePropCodeXInAnyof3Fields(db, callback) {
var things = [];
var tx = db.transaction('store');
var store = tx.objectStore('store');
var index = store.index('hasPropCodeX');
var request = index.openCursor();
request.onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
var thing = cursor.value;
things.push(thing);
cursor.continue();
} else {
callback(things);
}
};
request.onerror = function(event) {
console.error(event.target.error);
callback(things);
};
}
// Now that you have an api, here is some example calling code
// Not bothering to promisify it
function getData() {
var request = indexedDB.open(...);
request.onsuccess = function(event) {
var db = event.target.result;
getThingsWherePropCodeXInAnyof3Fields(db, function(things) {
console.log('Got %s things', things.length);
for(let thing of things) {
console.log('Thing', thing);
}
});
};
}

need to get data from a database nodejs

I have a server that is written in Java running Rhino for js,
and I decide to rewrite this server into nodejs...
And I need to get data from DB synchronous like :
function executeRowsetParam(sql, p){
return DB.raw(sql,p)// returns object
}
so I can use it like :
var userName = executeRowsetParam('SELECT user_name FROM users where user_id = ?', ["123"]);
if(userName.getRow(0).getValue("user_name ") == "admin"){
//do sth
}
is just an a simple example sometimes I need to select from database data that i have to use in like 1000 lines of code so code like :
executeRowsetParam('SELECT user_name FROM users where user_id = ?', ["123"]).then((r)=>{
if(r.getRow(0).getValue("user_name ") == "admin"){
//do sth
}
})
won't work so well ...
I have code like this too:
IfExists(SQL,p){
if(DB.raw("selecect top 1 1 from" + sql,p) == 1){
return true
}else{return false}
and rewriting it into :
DB.raw("selecect top 1 1 from" + sql,p).then((r)=>{
if(r == 1){//do sth}else{//do else}
})
won't work for me
so is there some npm package that I can use to make selects from db synchronuch that would make my day.
is code like this would be okey ?
var Start = async () => {
var Server = require("./core/server/Server");
console.log('hi!');
console.dir("there is nothing to look at at the momment");
var db = require("./core/db/DB");
global.DB = new db()
function foo() {
return DB.executeSQL("asdasd", [123, 123])
}
console.dir(await foo());
console.dir('asd');
global.DEBUG = true;
global.NEW_GUID = require('uuid/v4');
var server = new Server()
server.start();
}
Start();
is that enough to let me use await in every single instance inside the server or have I make every single function async if I would use await?
Found and tested deasync works great!
var deasync = require('deasync');
module.exports = function DB(){
var knex = require('knex')(require("./../../config").DB);
this.executeRowsetParam = (sql, param) => {
let done = false;
knex.raw(sql, param).then((r => {
done = r;
})).catch((e => {
throw "Error in query "+ e
}))
deasync.loopWhile(function () { return !done; });
return done
}
}

Use of indexedDB returns 'undefined'

I'm trying to use indexedDB.
Some parts of my code works.
In the following example, the first function adds server in my DB, however in Chrome debug console there is an undefined message not related to any line. The server is already added though.
The second function puts records in an array, there is also an undefined message not related to any line.
If I do a console.log(servers); just before return servers; I can see the array content, however if I call the function somewhere else in my code, the returned object is undefined.
var dbName = 'myDBname',
dbServersStoreName = 'servers',
dbVersion = 1,
openDBforCreation = indexedDB.open(dbName, dbVersion);
openDBforCreation.onupgradeneeded = function(e) {
var db = e.target.result;
var objStore = db.createObjectStore(dbServersStoreName, { keyPath: "alias"
});
var index = objStore.createIndex("serversAlias", ["alias"]);
};
function addServerInDB(serverAlias,serverAddress,user,pwd){
var myDB = indexedDB.open(dbName, dbVersion);
myDB.onerror = function() {
var notification = document.querySelector('.mdl-js-snackbar');
notification.MaterialSnackbar.showSnackbar(
{message: 'Error while trying to access internal database'});
}
myDB.onsuccess = function(e) {
var db = e.target.result,
request = db.transaction([dbServersStoreName],
"readwrite").objectStore("servers")
.put({alias:''+serverAlias+'',
address:''+serverAddress+'', login:''+user+'',
passwd:''+pwd+''});
request.onsuccess = function(){
var notification = document.querySelector('.mdl-js-snackbar');
notification.MaterialSnackbar.showSnackbar(
{message: 'Server added'});
}
}
};
function listServersInDB(){
var myDB= indexedDB.open(dbName, dbVersion);
myDB.onerror = function() {
var notification = document.querySelector('.mdl-js-snackbar');
notification.MaterialSnackbar.showSnackbar(
{message: 'Error while trying to access internal database'});
}
myDB.onsuccess = function(e) {
var servers = new Array(),
db = e.target.result,
request = db.transaction(["servers"], "readwrite")
.objectStore("servers")
.openCursor();
request.onsuccess = function(e){
var cursor = e.target.result;
if(cursor){
servers.push(cursor.value);
cursor.continue();
}
return servers;
}
}
};
I do not understand where this undefined comes from and if that is why the listServersInDB() function doesn't work.
You need to learn more about how to write asynchronous Javascript. There are too many errors in your code to even begin reasoning about the problem.
Briefly, don't do this:
function open() {
var openDatabaseRequest = ...;
}
openDatabaseRequest.foo = ...;
Instead, do this:
function open() {
var openDatabaseRequest = ...;
openDatabaseRequest.foo = ...;
}
Next, you don't need to try and open the same database multiple times. Why are you calling indexedDB.open twice? You can open a database to both install it and to start using it immediately. All using the same connection.
Next, I'd advise you don't name the database open request as 'myDB'. This is misleading. This is an IDBRequest object, and more specifically, an IDBOpenRequest object. A request isn't a database.
Next, you cannot return the servers array from the request.onsuccess at the end. For one this returns to nowhere and might be source of undefined. Two this returns every single time the cursor is advanced, so it makes no sense at all to return return servers multiple times. Three is that this returns too early, because it cannot return until all servers enumerated. To properly return you need to wait until all servers listed. This means using an asynchronous code pattern. For example, here is how you would do it with a callback:
function listServers(db, callbackFunction) {
var servers = [];
var tx = db.transaction(...);
var store = tx.objectStore(...);
var request = store.openCursor();
request.onsuccess = function() {
var cursor = request.result;
if(cursor) {
servers.push(cursor.value);
cursor.continue();
}
};
tx.oncomplete = function() {
callbackFunction(servers);
};
return 'Requested servers to be loaded ... eventually callback will happen';
}
function connectAndList() {
var request = indexedDB.open(...);
request.onsuccess = function() {
var db = request.result;
listServers(db, onServersListed);
};
}
function onServersListed(servers) {
console.log('Loaded servers array from db:', servers);
}
When you call a function that does not return a value, it returns undefined. All functions in JavaScript return undefined unless you explicitly return something else.
When you call a function from the devtools console, and that function returns undefined, then the console prints out '-> undefined'. This is an ordinary aspect of using the console.
If you want to get a function that returns the list of servers as an array, well, you cannot. The only way to do that in a pretend sort of way, is to use an 'async' function, together with promises.
async function getServers() {
var db = await new Promise(resolve => {
var request = indexedDB.open(...);
request.onsuccess = () => resolve(request.result);
});
var servers = await new Promise(resolve => {
var tx = db.transaction(...);
var request = tx.objectStore(...).getAll();
request.onsuccess = () => resolve(request.result);
});
return servers;
}
One more edit, if you want to call this from the console, use await getServers();. If you do not use the top-level await in console, then you will get the typical return value of async function which is a Promise object. To turn a promise into its return value you must await it.
Clear and helpfull explanations, Thank you.
I open database multiple times beacause the first time is for checking if DB needs an upgrade and doing something if needed. I'll add 'db.close()' in each functions.
Then, I tried your exemple and the result is the same:
console.log('Loaded servers array from db:', servers); works
but return servers; Don't work.
And in console there is already an undefined without related line :
Screenshot

How To handle result set of websql in html 5?

I m creating mobile web application using html5 and javascript.I m having two javascript files. AttributesDatabase.js and AttributeView.js.From AttributeView.js i m calling one function from AttributeDatabase.js in that i m executing one select query.Now the query result should go to AtttributeView.js.But the Websql transaction is asynchronous call that is what it is not returning proper result.Is there any way to handle the websql result.
Please help if any way there?
Edited
AttributeView.js
var AttributeDAOObj = new AttributeDAO();
AttributeDAOObj.GetAttributeList();
alert(AttributeDAOObj.GetAttributeList()); //This alert is coming as undefined.
AttributeDAO.js
this.GetAttributeList = function () {
var baseDAOObj = new BaseDAO();
var query = "SELECT AttributeName FROM LOGS";
// this.Successcalbackfromsrc = this.myInstance.Successcalback;
var parm = { 'query': query, 'Successcalback': this.myInstance.Successcalback };
baseDAOObj.executeSql(parm);
}
//To Create database and execute sql queries.
function BaseDAO() {
this.myInstance = this;
//Creating database
this.GetMobileWebDB = function () {
if (dbName == null) {
var dbName = 'ABC';
}
var objMobileWebDB = window.openDatabase(dbName, "1.0", dbName, 5 * 1024 * 1024);
return objMobileWebDB;
}
//Executing queries and getting result
this.executeSql = function (query) {
var objMobileWebDB = this.myInstance.GetMobileWebDB();
objMobileWebDB.transaction(function (transaction) {
//In this transaction i m returning the result.The result value is coming.
transaction.executeSql(query, [], function (transaction, result) { return result; }, this.Errorclback);
});
}
}
The problem is in you succes call back (like in the comment to your question, stated by DCoder)
function (transaction, result) { return result; }
this is returning where to?
So this is how to do it (or at least one way)
you can do for example:
function (transaction,result){
console.log("yes, I have some result, but this doesn't say anything, empty result gives also a result");
// so check if there is a result:
if (result != null && result.rows != null) {
if (result.rows.length == 0) {
// do something if there is no result
}else{
for ( var i = 0; i < result.rows.length; i++) {
var row = result.rows.item(i);
var id = result.rows.item(i).id; //supposing there is an id in your result
console.log('Yeah! row id = '+id);
}
}
}else{
// do something if there is no result
}
};
note the code above can be compacter, but this is how to understand it better.
another way is to put this function is a seperate piece of code, so you keep the sql statement more compact and readable. Like you call you error callback this can be in your function (with this. in front of it) or a completely seperate function.

Returning results from a JavaScript function

I'm fairly new to JavaScript and am hoping someone can help me understand how to modify the function below so it will properly return a result when called. The code currently works and the handleResults function is called once the session string is generated. What I would like to do is modify the generateSessionString function so it will return the session string rather than passing it to handleResults. Can anyone give me suggestions on how I can accomplish this?
function generateSessionString(){
var cb = function (success, results){
if(!success)
alert(results);
if(results.code && results.message){
alert (results.message);
return;
}
handleResults(results);
};
var config = new KalturaConfiguration(gPartnerID);
config.serviceUrl = gServiceURL;
var client = new KalturaClient(config);
var partnerId = gPartnerID;
var userId = gUserName;
var password = gPassWord;
var expiry = gExpiry;
var privileges = gPrivileges;
var result = client.user.login(cb, partnerId, userId, password, expiry, privileges);
return result;
}
function handleResults(ks){
KalturaSessionString = ks;
}
if you like to write it in a sync way(it's still async code) you can try promise(in this example i used jQuery)
function generateSessionString(){
var dfd = new jQuery.Deferred();
var cb = function (success, results){
if(!success)
dfd.fail(results);
if(results.code && results.message){
dfd.fail (results.message);
return;
}
dfd.resolve(results);
};
var config = new KalturaConfiguration(gPartnerID);
config.serviceUrl = gServiceURL;
var client = new KalturaClient(config);
var partnerId = gPartnerID;
var userId = gUserName;
var password = gPassWord;
var expiry = gExpiry;
var privileges = gPrivileges;
client.user.login(cb, partnerId, userId, password, expiry, privileges);
return dfd.promise();
}
$.when(generateSessionString()).then(
function(session)
{
alert(session);
}
)
#Itay Kinnrot's answer is right.Actually,jQuery's on/trigger is another way to solve it,but $.Deferred is better.
if you want to know more about it,you could try to understand Pub/Sub Pattern.
This article is recommended:
http://www.elijahmanor.com/2013/03/angry-birds-of-javascript-blue-bird.html

Categories