how to pass arguments to a function without invoking it directly - javascript

I am working on a database manager for an app. At a certain point I want to save some data like this:
//call the saveBillEvent
DatabaseManager.saveBillEvent(model, callbackfunc);
//accepts billeventmodel object
DatabaseManager.prototype.saveBillEvent = function(billEventModel, callback){
db.transaction(
RekeningDelen.DatabaseManager.databaseInstance,
RekeningDelen.DatabaseManager.saveBillEventSQL,
function(error) {
console.log(error);
console.log('transaction failed billeventspersons table creation ');
},
function(transactionId, result) {
console.log("transcation success billeventspersons, set firstappboot to false");
store.setItem("firstAppBoot", "false");
}
);
}
The saveBillEvent contains a transaction which at a given moment calls the saveBillEventSQL.
DatabaseManager.prototype.saveBillEventSQL = function(billEventModel, callback) {
//here i need the billEventModel to create the SQL
db.executeSql(
transactionId,
getAllBillEventsSQL,
null,
function(transactiondId, results) {
//here i want to call the callback
console.log('billevent saved ' + results);
},
function(response) {
alert('fail1');
console.log("SELECT billEvent query failed " + response);
}
);
}
This function contains the final callback, which should call the passed callback, for a certain query and also needs the billEventModel to create the query. Thus the billEventModel and the callback should be passed to this function, but that's not possible since the transaction triggers it at a specific moment.
So my question is how to deal with this A(with params)->B(has params, but cant pass through)->C(needs params) problem?
I hope you all can understand my question, if not add a comment.

Related

Get Value from parameter function

Sorry for the Noob Question. I'm trying to write a node.js function called "getTransitionId" that uses the jira-connector plugin to retrieve data for possible transitions for a particular issue.
The getTransitions function from the jira-connector takes two parameters: an object with the parameters of the ticket, and a function to execute once the call is finished.
Here's my problem: for reasons beyond the scope of this question, I want to access this data outside the function that's being passed as parameter to "getTransitions." But I can't figure out how. I understand that the last return statement (return "transitionData") is returning "undefined" because it's executing a return statement before the call is finished, but I don't know how to fix that.
Can I correctly use a callback in this case? If so, how would I use it in a function that is being passed as a parameter to another function?
const JiraApi = require('jira-connector');
const jira = new JiraApi( {
host: //Jira URL
basic_auth: {
//Authentication Information
}
});
function getTransitionId (ticketNumber, transition) {
jira.issue.getTransitions({
issueKey: ticketNumber,
}, function(error, transitions){
const transitionData = transitions['transitions'];
});
return transitionData;
}
Thanks for the help. Hope this made sense.
You could make your own getTransitionId function take a callback function as an argument. Here's an incomplete example (see ahead):
function getTransitionId (ticketNumber, transition, callback) {
jira.issue.getTransitions({
issueKey: ticketNumber,
}, function(error, transitions){
const transitionData = transitions['transitions'];
const id = /* ..get ID fron transitionData, somehow.. */
callback(id);
});
}
// Called like this:
getTransitionId(ticketNumber, transition, function(id) {
console.log("Got the ID:", id);
});
This isn't perfect, though. What if getTransitions has an error?
When you call jira.issue.getTransitions, you pass a callback function which takes two parameters: error and transitions. This is standard for functions which take callbacks in JavaScript - that is, callbacks usually take an error parameter (null or undefined if there was no error) and a data parameter (containing results of the action, like fetched transitions or an id).
We can change getTransitionId to take an error and then pass the error to the callback that you gave to getTransitionId:
function getTransitionId (ticketNumber, transition, callback) {
jira.issue.getTransitions({
issueKey: ticketNumber,
}, function(error, transitions){
if (error) {
callback(error);
return;
}
const transitionData = transitions['transitions'];
const id = /* ..get ID fron transitionData, somehow.. */
callback(null, id);
});
}
(Note that we use a return; statement inside if (error) -- that's so that we don't continue and try to use the transitions argument, which is probably undefined, since there was an error in jira.issue.getTransitions. This also prevents callback from being called a second time.)
Since we've added an error argument, we need to change how we call getTransitionId:
getTransitionId(ticketNumber, transition, function(error, id) {
if (error) {
console.error("There was an error fetching the transition ID:", error);
return;
}
console.log("Got the ID:", id);
}
(Since we do callback(null, id); in the code for getTransitionId, error will be null, so the code in if (error) { won't run. Of course, if there is an error, if (error) { will be run, and that's what we want!)
By adding code to handle errors passed to your callbacks, you make your code safer. Contrastingly, if you ignore error, you might end up having errors in your code that are hard to find - for example, you might have a TypeError because transitions is undefined, or see "Got the ID: undefined" in the log!

Javascript function doesn't return query result

I am trying to figure out why one of my queries won't return the value from a query...my code looks like this:
var client = new pg.Client(conString);
client.connect();
var query = client.query("SELECT count(*) as count FROM sat_scores")
// Don't use demo key in production. Get a key from https://api.nasa.gov/index.html#apply-for-an-api-key
function getNEO(callback) {
var data = '';
query.on('rows', function(rows) {
console.log("Row count is: %s", rows[0].count)
data += rows[0].count;
});
query.on('end', function() {
callback(data);
});
}
with that, getNEO returns a blank...but if I set var data = '4', then getNEO returns 4....the query should return 128 but it just returns a blank...
First of all, getNEO() doesn't return anything - I'm operating on the assumption that you call getNEO() exactly once for your query, and pass in a callback to handle the data, and that callback is what's not getting the appropriate data?
My typical recommendation for troubleshooting things like this is to simplify your code, and try and get really close to any example code given (for instance):
var client = new pg.Client(conString);
// define your callback here, in theory
client.connect(function (err) {
if (err) throw err;
var query = client.query("SELECT count(*) as count FROM sat_scores"),
function(err, result) {
if (err) throw err;
console.log(result.rows.length);
}
);
});
... I'm doing a couple things here you'll want to note:
It looks like the client.connect() method is asynchronous - you can't just connect and then go run your query, you have to wait until the connection is completed, hence the callback. Looking through the code, it looks like it may emit a connect event when it's ready to send queries, so you don't have to use a callback on the connect() method directly.
I don't see a data event in the documentation for the query object nor do I see one in the code. You could use the row event, or you could use a callback directly on the query as in the example on the main page - that's what I've done here in the interest of simplicity.
I don't see the count property you're using, and row[0] is only going to be the first result - I think you want the length property on the whole rows array if you're looking for the number of rows returned.
I don't know if you have a good reason to use the getNEO() function as opposed to putting the code directly in procedurally, but I think you can get a closer approximation of what you're after like this:
var client = new pg.Client(conString);
// define your callback here, in theory
client.connect();
function getNEO(callback) {
client.on('connect', function () {
var query = client.query("SELECT count(*) as count FROM sat_scores"));
query.on('end', function(result) {
callback(result.rowCount);
});
});
}
... so, you can call your getNEO() function whenever you like, it'll appropriately wait for the connection to be completed, and then you can skip tracking each row as it comes; the end event receives the result object which will give you all the rows and the row count to do with what you wish.
so here is how I was able to resolve the issue....I moved the var query inside of the function
function getNEO(state, callback) {
var conString = "postgres://alexa:al#alexadb2.cgh3p2.us-east-1.redshift.amazonaws.com:5439/alexa";
var client = new pg.Client(conString);
client.connect();
var data = '';
var query = client.query("SELECT avg(Math) as math, avg(Reading) as reading FROM sat_scores WHERE State = '" + state + "'");
console.log("query is: %s", query);
query.on('row', function(row) {
console.log("Row cnt is: %s", row.math);
console.log("row is: " + row)
data += row;
});
console.log("made it");
query.on('end', function() {
callback(data);
});
}

Passing additional parameters to callback

I am using mssql in node.js executing an SP:
var fnGetMapping = function(results) {
new sql.Request(db.sqlConnection)
.input('myParam', sql.VarChar(60), 'myValue')
.execute('usp_MySP', fnProcessUUIDData);
};
Now my fnProcessUUIDData looks like this:
var fnProcessUUIDData = function(err, recordsets) {
if (err) {
console.log("Error calling MS SQL: " + err.message);
} else {
if (recordsets[0].length > 0) {
} else {
};
}
};
What I need now is to pass one of my own parameter into fnProcessUUIDData.
I read some articles that this is possible but I couldn't get it working on my case, would appreciate some comments if what I want to do is possible.
You can use apply to pass some extra arguments without loosing the context.
new sql.Request(db.sqlConnection)
.input('myParam', sql.VarChar(60), 'myValue')
.execute('usp_MySP', function(...args) {
fnProcessUUIDData.apply(this, args.concat(some, extra, parameters));
});
var fnProcessUUIDData = function(err, recordsets, some, extra, parameters) {
console.log(this, some, extra, parameters);
};
Using apply overcomplicates things because fnProcessUUIDData is a plain old function and not a method (it doesn't use this internally). All you need to do is wrap it in another function:
new sql.Request(db.sqlConnection)
.input('myParam', sql.VarChar(60), 'myValue')
.execute('usp_MySP', function(err, recordsets) {
fnProcessUUIDData(err, recordsets, additional_parameter);
});

javascript http call not working

I am working with javascript for quite some time now and recently started using Nodejs in my project. I have a requirement to make some http calls from my nodejs app and then when all of them are done, need to consolidate and send the response.
In this regards, I was searching and came across async module for Nodejs. (https://github.com/caolan/async)
I also found a blog which nicely explains how to use this feature. (http://justinklemm.com/node-js-async-tutorial/)
The below code snippet is what I am planning to use for my task.
// Include the async package
// Make sure you add "async" to your package.json
async = require("async");
// 1st para in async.each() is the array of items
async.each(items,
// 2nd param is the function that each item is passed to
function(item, callback){
// Call an asynchronous function, often a save() to DB
item.someAsyncCall(function (){
// Async call is done, alert via callback
callback();
});
},
// 3rd param is the function to call when everything's done
function(err){
// All tasks are done now
doSomethingOnceAllAreDone();
}
);
In the above I need to make http call instead of item.someAsyncCall section. Specifically the code that I have is
var formaatedResponse=[];
request("http://" + API_HOST + "/app/v1/customers/" + element,
function (error, response, body) {
console.log('Ajax call response');
formaatedResponse.push(JSON.parse(response.body));
});
How to accommodate my changes since when I tried adding the above code it does not work as intended.
My code:
function consolidateResponse(){
console.log("Everything is done.");
console.log(formaatedResponse);
}
// 1st para in async.each() is the array of items
async.each(result,
// 2nd param is the function that each item is passed to
function(element, callback){
// Call an asynchronous function, often a save() to DB
request("http://" + API_HOST + "/app/v1/customers/" + element, function (error, response, body) {
console.log('Ajax call response');
formaatedResponse.push(JSON.parse(response.body));
});
callback();
},
// 3rd param is the function to call when everything's done
function(err){
// All tasks are done now
consolidateResponse();
}
);
Regards,
Pradeep
You should call callback() inside request()'s callback:
request("http://" + API_HOST + "/app/v1/customers/" + element,
function (error, response, body) {
console.log('Ajax call response');
formaatedResponse.push(JSON.parse(response.body));
callback();
});
This way you're signalling you're done with the particular item when http request actually finishes instead of right after it starts.
I expect that moving the callback into your call should resolve the issue:
// 1st para in async.each() is the array of items
async.each(result,
// 2nd param is the function that each item is passed to
function (element, callback) {
// Call an asynchronous function, often a save() to DB
element.someAsyncCall(function () {
request("http://" + GLASS_API_HOST + "/glass/v1/vmware/vm/" + element, function (error, response, body) {
console.log('Ajax call response');
formaatedResponse.push(JSON.parse(response.body));
/*Changed:*/ callback();
});
});
},
// 3rd param is the function to call when everything's done
function (err) {
// All tasks are done now
consolidateResponse();
}
);
Explanation:
In the previous code, the callback was called immediately after a request was issued, without waiting for the response. By moving the callback to the internal function of the request, you make sure it will not be called before the response is returned.
Also note async.each() works in parallel for all items, so if your result set is extemely large you may want to consider using async.eachLimit which will limit parallel requests to a defined value, or async.eachSeries which will make sure execution of requests is in series.
Another suggestion:
You can utilize the callback to handle errors, this way:
request("http://" + GLASS_API_HOST + "/glass/v1/vmware/vm/" + element, function (error, response, body) {
if(error){
callback(error);
return
}
console.log('Ajax call response');
formaatedResponse.push(JSON.parse(response.body));
callback();
});
And then async.each callback:
// 3rd param is the function to call when everything's done
function (err) {
if (err) {
// Handle error here: log it, report it, and return response with err code. example:
console.error(err);
// Halt execution;
return;
}
// All tasks are done now, and no error occurred:
consolidateResponse();
}
So your final code might look like:
// 1st para in async.each() is the array of items
async.each(result,
// 2nd param is the function that each item is passed to
function (element, callback) {
// Call an asynchronous function, often a save() to DB
element.someAsyncCall(function () {
request("http://" + GLASS_API_HOST + "/glass/v1/vmware/vm/" + element, function (error, response, body) {
if (error) {
callback(error);
return
}
console.log('Ajax call response');
formaatedResponse.push(JSON.parse(response.body));
callback();
});
});
},
// 3rd param is the function to call when everything's done
function (err) {
if (err) {
// Handle error here: log it, report it, and return response with err code. example:
console.log(err);
// Halt execution;
return;
}
// All tasks are done now, and no error occurred:
consolidateResponse();
}
);

Parse.com Cloud Code - Creating new Instance of another object on before save

I have two classes, Groups and memberships. When a group is made, I'd like its corresponding membership to be made as well. I attempt to do so like this:
Parse.Cloud.beforeSave("Group", function(request, response) {
var name = request.object.get("name");
if (!name) {
response.error("A Group must have a name");
} else {
if (!(/^\w+$/i.test(name))){
response.error("Only letters and numbers, please.");
}
var query = new Parse.Query("Group");
query.equalTo("name", name);
query.first({
success: function(object) {
if (object) {
response.error("A group with this name exists.");
} else {
createMembershipForGroup(request.object, Parse.User);
response.success();
}
},
error: function(error) {
response.error("Could not validate Uniqueness");
}
});
}
});
createMembershipForGroup = function(group, user) {
var MembershipClass = Parse.Object.extend("Membership");
var membership = new MembershipClass();
membership.set("group", group);
membership.set("user", user);
membership.save(null,{
success:function(membership) {
response.success(membership);
},
error:function(error) {
response.error(error);
}
});
}
I receive an error back, saying the following:
E2014-05-06T21:40:10.740Z] v30: before_save triggered for Group for
user xgzDnZ9h0A Input:
{"original":null,"update":{"admin":{"objectId":"xgzDnZ9h0A","className":"_User","__type":"Pointer"},"name":"test","public":false}}
Result: undefined
Not too sure what the error is. How could I go about debugging code like this so I can isolate the issue easily?
Let beforeSave handle only the validation, and move your membership code to afterSave. The problem is probably that you're trying to store a relation to an object that is not yet saved (as you're in beforeSave, the object does not yet have an objectId)
problem is you are trying to call an async function and leaves before wait to complete it.
createMembershipForGroup(request.object, Parse.User);//Calling async func
response.success();//Leaves beforeSave function
You should write your createMembershipForGroup function inside success response of your query and return your response.success() method in here
membership.save(null,{
success:function(membership) {
response.success(membership); // this should be response of beforeSave
},
error:function(error) {
response.error(error);
}
});
I will post working code if this not helps.

Categories

Resources