Inserting into SQLite database with parameters - javascript

I am building a cross-platform app using AngularJS, Monaca and OnsenUI.
I have implemented a SQLite database to save data to be able to work offline. My implementation is based on the answer found HERE
I have a view where the user can select any number of options and those option values should then be saved to the SQLite database. Each option value can be saved to the same database table or separate tables - depending on the option value selected.
With this I am trying to refactor my insert statement to make it more efficient as it may be called many times. In my app.js controller I have a function that checks which option value was selected in the view, and then calls the goInsert() function that inserts the selected option value into the SQLite Database. Below is a sample of my function.
$scope.selectedIDOne = ""; // Variable to hold selected options value
$scope.changedValue = function (item, identifier) // item = selected option value; identifier = identifies table name to insert into
{
switch (identifier)
{
case "Square":
$scope.selectedIDOne = item;
db.transaction(goInsert(identifier), errorCB, successCB); // Error on refactored goInsert(identifier) function trying to pass identifier
break;
default:
// TODO
}
}
Then I try the following in my goInsert() function.
function goInsert(identifier) // Error here
{
switch (identifier)
{
case "Square":
db.transaction(insertSquareDB, errorCB, successCB);
break;
}
}
function insertSquareDB(tx)
{
tx.executeSql('INSERT OR IGNORE INTO tb_square (square_id) VALUES ("' + $scope.selectedIDOne + '" )');
}
When I run the code I get an error where indicated but the value is nonetheless inserted int the database. The error is thrown at the goInsert(identifier) function call. The error is:
TypeError: Failed to execute 'Transaction' on 'Database'. The callback provided as parameter 1 is not a function.
How can I implement this solution please? Or is there a better way? I would also ideally not like to create multiple insertSquareDB(tx) functions e.g. insertCircleDB(tx), insertROundDB(tx) etc. Is there a way I can have 1 function defined that inserts values dynamically e.g. (hypothetical)
function insertSquareDB(tx, tableName, columnName, optionValues)
{
tx.executeSql('INSERT OR IGNORE INTO tableName (columnName) VALUES ("' + optionValues + '" )');
}

You don't need to wrap your goInsert(identifier) call inside a transaction:
switch (identifier)
{
case "Square":
$scope.selectedIDOne = item;
goInsert(identifier);
...
}
If you want to be able to call one function to insert any shape into the database, your best bet is to dynamically generate the SQL statement:
function insertShapeDB(shape, value)
{
var tableName = '';
var columnName = '';
if (shape === 'Square') {
tableName = 'tb_square';
columnName = 'square_id';
}
else if (shape === 'Circle') {
tableName = 'tb_circle';
columnName = 'circle_id';
}
else if (shape === 'Round') {
tableName = 'tb_round';
columnName = 'round_id';
}
var sql = 'INSERT OR IGNORE INTO ' + tableName + ' (' + columnName + ') VALUES (?)';
db.transaction(function(tx) {
tx.executeSql(sql, [value]);
});
}

Related

How do I reject writing value to Firebase if have the same value in my DB? (Javascript)

I'm creating my custom order id with auto-increment generator function for my project. I will state my question here, if you want to know the whole story please read below.
As written in the title, I need a way to reject my set to Firebase and it has to be done in 1 query. Currently, it will write my orderID to Firebase without rejecting it. But I need to reject if there is the same ID in the table.
The short version of my code will be posted here, the whole function will be posted below.
firebase.database().ref('orderCounter/orderIDsChecker/'+orderID).set({
id: orderID,
}, function(error) {
if (error) {
console.log('Order ID fail to generate. Regenerating new ID')
createOrderID(orderCounterRef);
} else {
console.log('Order ID created!')
}
});
}
The story,
I'm creating my own custom order id with auto-increment generator function for my project. The problem is that if multiple users creating order at the same time, it will generate the same id. Yes, I can use transaction() to solve the problem but I have no idea how to use it. Therefore, I have created my own version of the "transaction". With my method, I am able to prevent duplicates id unless 2 or more users create order within 1 second of gap. Or if anyone is kind enough to show me an example of how to write a transaction for my function, I thank you in advance.
The flow of the code is,
Get "currentMonth" and "orderIdCounter" from Firebase -> orderIdCounter +1 and update to Firebase -> start the process of generating order id -> Send the generated id to firebase -> If return success "order ID created", If not "got duplicate id" Re-run the whole process.
Below is the code for my order id generator function.
function createOrderID(orderCounterRef){
var childData = [];
var orderID;
//Get the Current Month and Order ID Counter from Firebase
orderCounterRef.on('value', function(snap) { childData = snapshotToArrayWithoutID(snap); });
var currentMonth = childData[0];
var orderIDCounter = childData[1];
if (orderIDCounter !== undefined){
//Update orderIDCounter on Firebase.
//This is to prevent duplicate orderID when multiple users is creating order at the same time.
var IDCounter = parseInt(orderIDCounter) + 1;
//Set IDCounter to 3 digits
IDCounter = ('00' + IDCounter.toString()).slice(-3);
firebase.database().ref('orderCounter/orderIDCounter').set(IDCounter);
//Handle the process to generate Order ID. Return in YYMMxxx(auto increment) format.
orderID = handleCreateOrderID(currentMonth, (parseInt(orderIDCounter) - 1));
//Check if duplicate ID on firebase
firebase.database().ref('orderCounter/orderIDsChecker/'+orderID).set({
id: orderID,
}, function(error) {
if (error) {
console.log('Order ID fail to generate. Regenerating new ID')
createOrderID(orderCounterRef);
} else {
console.log('Order ID created!')
}
});
}
return orderID;
}
My DB:
You should indeed use a transaction as you have mentioned in your question.
The following should do the trick:
//Declare a function that increment a counter in a transaction
function createOrderID() {
var orderIdRef = firebase.database().ref('orderId');
return orderIdRef.transaction(function(currentId) {
return currentId + 1;
});
}
//Call the asynchronous createOrderID() function
createOrderID().then(function(transactionResult) {
console.log(transactionResult.snapshot.val());
});
If you want to start the counter at a specific value, just create an orderId node in your database and assign a specific value to it, e.g; 1912000.
If you just want to start at 1, you don't need to create a node, it will be automatically created with the first call to the createOrderID() function.
Thank you, #samthecodingman & #Renaud Tarnec for your advice.
I took #samthecodingman's code and change a bit to fit my project. But I use generateOrderID() only to call the result and it works well. But you won't get any value with just the code. I call out another function (connectToFirebase) whenever users enter the page. I am not sure why it works or if this is the right way, but it works for me and that's good enough.
export function generateOrderID(){
var orderId;
var childData = [];
const orderCounterRef = firebase.database().ref('orderCounter/');
//Get the Current Month from Firebase
orderCounterRef.on('value', function(snap) { childData = snapshotToArrayWithoutID(snap); });
//Check ID format YYMMXXX (XXX=auto_increment). Hanlde auto_increment for Year and Month
handleOrderIdFormat(childData[0], orderCounterRef)
//transaction
orderCounterRef.child('orderId').transaction(function(currentId) {
orderId = (currentId||0) +1;
return orderId;
}, function(err) {
if( err ) {
console.log(err)
}
});
return orderId;
}
export function connectToFirebase(){
//Connection Firebase Database
const orderCounterRef = firebase.database().ref('orderCounter/');
orderCounterRef.on('value', function(snap) { });
}

Retrieve Multiple Enitiies in Dynamics CRM using OData

I have a ribbon button command which executes a javascript function and passes in the selected rows in a grid. I am looping through that list to create a $select filter to make a RetrieveMultiple request.
The problem is everytime I get the following error
400: Bad Request: No Property 'id' exists in type 'Microsoft.Xrm.Sdk.Entity' at position 1
I have tried with id instead of Id but I still get the same error.
My code is below
function approveMultipleApplications(selectedApplicationReferences) {
if (selectedApplicationReferences && selectedApplicationReferences.length > 0) {
var filter = '';
for (var i = 0; i < selectedApplicationReferences.length; i++) {
filter += '(id eq guid\'' + selectedApplicationReferences[i].Id + '\')';
if (i < selectedApplicationReferences.length - 1) {
filter += ' or ';
}
}
var options = "$select=new_assessmentcount,new_requiredassessmentcount&$filter=" + filter;
try {
SDK.REST.retrieveMultipleRecords("new_application", options, retrieveApplicationsCallBack, function (error) {
alert(error.message);
}, retrieveComplete);
}
catch (ex) {
Xrm.Utility.alertDialog('Something went wrong, please try again or contact your administrator ' + ex, null);
}
}
else {
Xrm.Utility.alertDialog('You must select at least one application to approve', null);
}
}
The selectedApplicationReferences[i].Id is in this format {guid-value}
Any help or guidance is appreciated
The error message is pretty much spot on: Use LogicalNameId instead of just Id. In your case that would be new_applicationId:
filter += '(new_applicationId eq guid\'' + selectedApplicationReferences[i].Id + '\')';
It can be a bit confusing since there is actually no Id-field in the database. If you use e.g. early bound classes, the Id field is set for you behind the scenes, so that might have confused you. The Id field is not returned by the OData endpoint.

NodeJS MSSQL WHERE IN Prepared SQL Statement

I am use nodejs npm package sql
I currently have an array of product skus like so..
var skus = ['product1', 'product2', 'product3'];
My sql store in a file as follows...
SELECT *
FROM stock AS s
WHERE s.sku IN (#skus)
Then I also have my prepared statement code as follows..
var connection = new sql.Connection(config, function(err) {
var ps = new sql.PreparedStatement(connection);
//Add params
if(params != undefined){
for(var key in params){
ps.input(key, sql.VarChar(200));
}
}
ps.prepare(sqlstatement, function(err) {
ps.execute(params, function(err, data) {
callback(null, data);
ps.unprepare(function(err) {
});
});
});
});
}
skus is contained correctly within the params object as the statement works fine when I am using it for simple WHERE X = #YI am just struggling with how I need pass the array of skus to allow them to work in the prepared statement.
I am amend the string using split and join to comma seperate them etc etc but I can't get these methods to work.
I assumed that I would need the param string to look like the following 'product1','product2','product3'.
would be also useful if someone could shed some light on how to debug the completed prepared statement so I can see what is actually being queried to SQL (with params inplace)
Many thanks in advance!
It appears that the sql object (i.e. the mssql module) has no attribute to handle arrays of anything. Moreover, specifying a scalar type in the call to ps.input similarly does not work.
The next best thing is to build keys for your array of parameters into your sql statement itself:
var connection = new sql.Connection(config, function(err) {
var ps = new sql.PreparedStatement(connection);
// Construct an object of parameters, using arbitrary keys
var paramsObj = params.reduce((obj, val, idx) => {
obj[`id${idx}`] = val;
ps.input(`id${idx}`, sql.VarChar(200));
return obj;
}, {});
// Manually insert the params' arbitrary keys into the statement
var stmt = 'select * from table where id in (' + Object.keys(paramsObj).map((o) => {return '#'+o}).join(',') + ')';
ps.prepare(stmt, function(err) {
ps.execute(paramsObj, function(err, data) {
callback(null, data);
ps.unprepare(function(err) {
});
});
});
});
}

OrientDB function error when accessing query result

I have the following function in OrientDB studio, the functions saved with no problem:
var entities= db.query("select Name from F__Entity_Master");
getTemplate(0);
function getTemplate(index){
if (index >= entities.length){
return entities;
} else {
var sql = "select from F__Subjects where subjectCode='"+ entities[index]['#class']+"'";
var template = db.query(sql);
entities[index]['template']= template;
index += 1;
getTemplate(index);
}
}
Running the function in studio generates the following error:
Erroronparsingscriptatposition#0: ErroronexecutionofthescriptScript: GetEntities------^sun.org.mozilla.javascript.internal.EvaluatorException: Javaclass"com.orientechnologies.orient.core.record.impl.ODocument"hasnopublicinstancefieldormethodnamed"template".(#12)inatlinenumber12Javaclass"com.orientechnologies.orient.core.record.impl.ODocument"hasnopublicinstancefieldormethodnamed"template".(#12)
I used recursion to avoid using null values before fetching data from database. Using for loop generates similar error.
There are no relations between F__Subjects and F__Entity_Master as for every F__Subjects record a relevant class named with subjectCode field of F__Subjects record is generated and inherited from the F__Entity_Master. So the only way to detect relation is to use the subjectCode field to get the class meta information from he F__Subjects class.
Any ideas?
Solved
I used Lvca hint and here is the correct version of the function after few trials:
var entities= db.query("select from F__Entity_Master");
getTemplate(0);
return entities
function getTemplate(i){
if (i >= entities.length){
return ;
} else {
var sql = "select from F__Subjects where subjectCode='"+ entities[i].getClassName()+"'";
var template = db.query(sql);
entities[i].field('template', template[0].toMap());
i += 1;
getTemplate(i);
}
}
entities is an array of ODocument, so to get/set a field you should use respectively the field(name) and field(name,value) methods.
try field.getProperty()
this worked for me when writing functions in javascript for the orientdb server

Passing parameter in javascript function is giving error

I am using extjs grid , and i put a render function on a coloumn of a grid
/**
* function for rendering the link
**/
function linkRenderer(data, cell, record, rowIndex, columnIndex, store) {
console.log(record.id);
if (data != null) {
return '' + data + '';
}
return data;
}
while on clicking the link i got an error that whatever the value of record.id is not not defined
Please suggest what solution i can do .
Do you have a idProperty set for your store? set the idProperty to one of the values used to identify unique records. This will ensure that record.id is set to a value. For accessing all other values of the record, you will have to access them through record.data.proerty
Update: You need to use escape characters so that the string values are properly passed to the resellerwindow method:
+ data + ''
But that's pretty clear the value of record.id is not define. Dah!
If the output of your console log is a string you are calling your function wrong, you are missing some quotes if record.id is a string.
function linkRenderer(data, cell, record, rowIndex, columnIndex, store) {
if (data != null) {
return String.format('{1}', record.id, data);
}
return data;
}

Categories