parameterized execute query breaking due to wrong string concatenation in appcelerator - mysql

I am trying to execute an INSERT query using db.execute using the Appcelerator APIs. As per its docs it should be ideally used as :
var thisName = 'Arthur';
var thisPhoneNo = '1-617-000-0000';
var thisCity = 'Mountain View';
db.execute('INSERT INTO people (name, phone_number, city) VALUES (?, ?, ?)', thisName, thisPhoneNo, thisCity);
Database execute API doc for Appcelerator
So here is my problematic code which is almost blinding me:
var _tbl = "g_work_docket";
var records = [{
"id" : "2134",
"accession_no" : "20043446",
"opened" : "2014-07-25",
"job_origin" : "TRAMS Inspection",
"deadline" : "2014-09-30",
"completed_by" : "naren",
"completed" : "2016-02-18",
"mitigation_option" : "",
"location_no" : "186:03:",
"notes" : "",
"comments" : "",
"priority" : null,
"status" : "closed",
"is_approved" : "0",
"reviewer_comments" : "",
"updated_at" : "2016-02-18 12:58:50",
"is_deleted" : "0",
"site" : "K"
}, {
"id" : "3016",
"accession_no" : "196920850",
"opened" : "2000-01-19",
"job_origin" : "TRAMS Inspection",
"deadline" : "2001-01-01",
"completed_by" : "naren",
"completed" : "2016-02-18",
"mitigation_option" : "",
"location_no" : "770:01:",
"notes" : "Further inspection :\n\nDecay assesment : microdrill trunk base",
"comments" : "",
"priority" : null,
"status" : "closed",
"is_approved" : "0",
"reviewer_comments" : "",
"updated_at" : "2016-02-18 13:26:14",
"is_deleted" : "0",
"site" : "W"
}];
_.each(records, function(record) {
var qry = "INSERT OR REPLACE INTO " + _tbl + " (";
_.each(record, function(value, key, list) {
qry += '' + key + ',';
});
qry = qry.slice(0, -1);
qry += ") VALUES (";
_.each(record, function(value, key, list) {
qry += '?,';
});
qry = qry.slice(0, -1);
qry += "),";
_.each(record, function(value, key, list) {
qry += "'" + value + "',";
});
qry = qry.slice(0, -1);
db.execute(qry);
});
This always errors saying:
[ERROR] : Error: near "'2134'": syntax error (code 1): , while compiling: INSERT OR REPLACE INTO g_work_docket (id,accession_no,opened,job_origin,deadline,completed_by,completed,mitigation_option,location_no,notes,comments,priority,status,is_approved,reviewer_comments,updated_at,is_deleted,site) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?),'2134','20043446','2014-07-25','TRAMS Inspection','2014-09-30','naren','2016-02-18','','186:03:','','','null','closed','0','','2016-02-18 12:58:50','0','K'

Resolved this issue by passing the values by pushing them into an array first and then passing it to the db.execute function's 2nd param.
_.each(records, function(record) {
var qry = "INSERT OR REPLACE INTO " + _tbl + " (";
var dataValues = [];
_.each(record, function(value, key, list) {
qry += '' + key + ',';
});
qry = qry.slice(0, -1);
qry += ") VALUES (";
_.each(record, function(value, key, list) {
qry += '?,';
});
qry = qry.slice(0, -1);
qry += ")";
_.each(record, function(value, key, list) {
dataValues.push(value);
});
db.execute(qry, dataValues);
});

Related

JSON value to be print by Python

I have created a script where I need to get each details of user that is being generated in JSON. What could be the possible way in order for me display the "name": "admin"?
Please see script below.
`
import xmlrpc.client
import json
class TestlinkAPIClient:
# substitute your server URL Here
SERVER_URL = "https://testserver"
def __init__(self, devKey):
self.server = xmlrpc.client.ServerProxy(self.SERVER_URL)
self.devKey = devKey
def getUserByLogin(self):
for userDetail in self.server.tl.getUserByLogin(dict(devKey=self.devKey,user='user1')):
user_status = int(userDetail.get("isActive")) #json(userDetails.json) value isActive = 1 else isActive = 0 for not active
lastname = userDetail.get("lastName")
firstname = userDetail.get("firstName")
userLogin = userDetail.get("login")
activeStatus = ("Active User")
globalrole = userDetail.get("globalRole")
tproject = userDetail.get("tprojectRoles")
#for role in tproject.values():
for projectID in tproject:
user_detail = (userLogin + " " + lastname + " " + firstname + " " + str(globalrole['name']) + " " + "ProjectID: " + projectID)
print(user_detail)
# substitute your Dev Key Here
client = TestlinkAPIClient("testlinkApiKey")
details = client.getUserByLogin()
with open('./DebugProjectRoleDetails.json', 'w') as f:
json.dump(details , f)
and here is the sample json format, hhere I should get an output of the "name": "admin"
[
{
"firstName": "UserFirst",
"lastName": "UserLast",
"emailAddress": "first.last#morpho.com",
"locale": "fr_FR",
"isActive": "1",
"defaultTestprojectID": "",
"globalRole": {
"name": "projectadmin",
}
"globalRoleID": "10",
"tprojectRoles": {
"1234": {
"name": "admin"
}
}
]
expected output:
0001 User projectadmin ProjectID: 1001 projectRoles=viewer
If userDetail is in a JSON file and you want to save it as a dictionary, so you can use the get() method, you need to use json.load:
import json
with open('./user.json') as f:
details = json.load(f)
Since tproject is also a dictionary you need to use get() to extract the role (value) corresponding to the project (key)
for userDetail in details:
user_status = int(userDetail.get("isActive"))
lastname = userDetail.get("lastName")
firstname = userDetail.get("firstName")
userLogin = userDetail.get("login")
activeStatus = ("Active User")
globalrole = userDetail.get("globalRole")
tproject = userDetail.get("tprojectRoles")
# for role in tproject.values():
for projectID in tproject:
role = tproject.get(projectID)
user_detail = f"{userLogin} {lastname} {firstname} {str(globalrole['name'])} ProjectID: {projectID} {role}"
print(user_detail)
ouput using your JSON sample:
None UserLast UserFirst projectadmin ProjectID: 1234 {'name': 'admin'}
I have noticed that it is possible to declare 2 items in a for loop.
dictionary_item_tproject = tproject.items()
for projectID,projectRole in dictionary_item_tproject:
print(userLogin + " " + lastname + " " + firstname + " " + str(globalrole['name']) + " " + str(projectID) + " " +str(projectRole['name']))
This solve my problem. Now I am able to parse JSON properly. Thanks everyone.

How do I insert a mysql row from Object (in nodeJS)?

Right now I use this cumbersome approach when I want to add a row whose data is in a JS Object
Adding a row to a table:
const mysql = require('mysql')
var db = mysql.createConnection(DBInfo)
var databaseObj = {val1: '1', name: 'John', age: 40} // row to insert
var query = 'INSERT INTO my_table ('
var databaseKeys = Object.keys(databaseObj)
for (let i = 0; i < databaseKeys.length; i++) {
query += databaseKeys[i] + (i !== databaseKeys.length - 1 ? ', ' : ')')
}
query += ' ' + 'VALUES('
for (let i = 0; i < databaseKeys.length; i++) {
query += '\'' + databaseObj[databaseKeys[i]] + '\'' + (i !== databaseKeys.length - 1 ? ', ' : ')')
}
db.query(query, function (err, results, fields) {...
Is there any simpler or neater way to add a row into a table, where such row data is in a JS Object? The examples I see around use an array of arrays, but in my case the info is in a Object
I should use the INSERT into table SET because they are equivalent
var db = mysql.createConnection(DBInfo)
var databaseObj = {val1: '1', name: 'John', age: 40}
var query = 'INSERT INTO my_table SET ' + db.escape(databaseObj)
db.query(query, function (err, results, fields) {...

Node.js chaining promises in a loop with MySQL

I am trying to make a non-relational DB into a relational DB. So I am starting from data with no unique IDs.
I need to get the result from one SQL call loop through those rows, and for each one, do a SQL SELECT using part of the first result, then another SQL select using the next result, and then a write using IDs from the first and last queries.
I am using Node.js and ES6 promises to keep everything in order, but I seem to be missing something. I was actually trying to do an extra SQL call, and also use that result in the third query, but I am simplifying it to just get one call to feed into another.
Maybe some code will help show what I am trying to do.
Here is my query class that returns promises:
var mysql = require('mysql');
class Database {
constructor() {
this.connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "root",
database: "pressfile"
});
}
query(sql, args) {
return new Promise((resolve, reject) => {
this.connection.query(sql, args, (err, result, fields) => {
if (err) return reject(err);
resolve (result);
});
});
}
close() {
return new Promise((resolve, reject) => {
this.connection.end(err => {
if (err) return reject (err);
resolve();
});
});
}
}
This was stolen pretty much as is from a tutorial site, and this part seems to work pretty well. Then here comes the loop, and the multiple queries:
var contactId;
var address1;
var orgName;
var database = new Database();
database.query("SELECT * FROM contact")
.then( result => {
for (var i = 0; i < result.length; i++) {
contactId = result[i].contactId;
orgName = result[i].org;
var sql2 = "SELECT * FROM organization WHERE (name = \"" + orgName + "\")";
console.log(sql2);
database.query(sql2)
.then(result2 => {
console.log(result2);
var orgId = result2[0].organizationId;
var sql3 = "INSERT INTO contact_organization (contactId, organizationId) VALUES (" + contactId + ", " + orgId + ")";
console.log(sql3);
return ""; //database.query(sql3);
}).then( result3 => {
console.log(result3);
});
}
}).catch((err) => {
console.log(err);
databse.close();
});
I know it is kind of unraveling at the end, but I'm not wanting to do the INSERT query until I know I can get it right. Right now in the console, I get a valid organization object, followed by:
`INSERT INTO contact_organization (contactId, organizationId) VALUES (17848, 29)'
17848 is the final contactId that is returned in the for loop. How can I get the contactId that is assigned before the second query. I know I am not doing this asynchronous stuff right.
Try something like this. Just a quick solution. (not tested).
const selectOrg = (result) => {
contactId = result[i].contactId;
orgName = result[i].org;
var sql = "SELECT * FROM organization WHERE (name = \"" + orgName + "\")";
return database.query(sql);
};
const insertOrg = (result) => {
var orgId = result[0].organizationId;
var sql = "INSERT INTO contact_organization (contactId, organizationId) VALUES (" + contactId + ", " + orgId + ")";
return database.query(sql);
};
database.query("SELECT * FROM contact")
.then(result => {
const promises = [];
for (var i = 0; i < result.length; i++) {
promises << selectOrg(result)
.then(insertOrg);
}
return Promise.all(promises);
})
.then(allResults => {
console.log(allResults);
})
.catch((err) => {
databse.close();
});
I found a way to do this, but it is kind of cheesy. I included the contactId as a constant in the SQL query to get the organization, so I could then pass the value to the .then, keeping everything in order.
My sql2 statement becomes:
var sql2 = "SELECT *, " + contactId + " AS contactId FROM organization WHERE (name = \"" + orgName + "\")";
Then when that query returns, I can just pull the correct contactId out as result[0].contactId, from the same result I get the organizationId from.
Here is the final code:
database.query("SELECT * FROM contact")
.then( result => {
for (var i = 0; i < result.length; i++) {
var contactId = result[i].contactId;
var orgName = result[i].org;
var sql2 = "SELECT *, " + contactId + " AS contactId FROM organization WHERE (name = \"" + orgName + "\")";
database.query(sql2)
.then(result2 => {
var orgId = result2[0].organizationId;
var contactId = result2[0].contactId;
var sql3 = "INSERT INTO contact_organization (contactId, organizationId) VALUES (" + contactId + ", " + orgId + ")";
console.log(sql3);
return database.query(sql3);
}).then( result3 => {
console.log(result3);
});
}
}).catch((err) => {
console.log(err);
databse.close();
});
The console.log(result3) returns a bunch of these:
OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '',
protocol41: true,
changedRows: 0 }
And I got one contact_organization inserted for every contact row returned from the first query.

How to build dynamic query by binding parameters in node.js-sql?

I'm using nodejs-mysql module to do query in node.js recently, and in my working case I could only use the parameter-binding syntax like:
SELECT * FROM table WHERE name = ?
Now I want to build dynamic sql with these ? OR ?? parameters. Assume that I have 2 conditions(name and age) which either of them could be null (if user doesn't provide it),
So I want to build MySQL in 3 cases:
only name=Bob: SELECT * FROM table WHERE name = 'Bob'
only age=40: SELECT * FROM table WHERE age > 40
both: SELECT * FROM table WHERE name = 'Bob' AND age > 40
I know it's easy if you build the query on your own, but how can I achieve it when using placeholders which can only bind field or values ?
In document of nodejs-mysql, placeholder ? only stands for values and ?? stands for fields:
https://github.com/felixge/node-mysql/#escaping-query-values
https://github.com/felixge/node-mysql/#escaping-query-identifiers
My first thinking of solution is to insert query piece by using these placeholders, but it comes to failure because both ? and ?? will escape my query piece, and my query will be executed incorrectly.
My code so far is as below, which I'm defenitly sure it's not correct because query piece has been escaped:
// achieve paramters from url request
var condition = {};
if(params.name)condition["name"] = ["LIKE", "%" + params.name + "%"];
if(params.age)condition["age"] = parseInt(params.age, 10);
//build query
var sqlPiece = buildQuery(condition);
//try to replace ? with query
var sql = 'SELECT * FROM table WHERE ?';
connection.query(sql, sqlPiece, function(err, results) {
// do things
});
// my own query build function to proceed conditions
function buildQuery(condition) {
var conditionArray = [];
for(var field in condition){
var con = condition[field];
if(con !== undefined){
field = arguments[1] ? arguments[1] + "." + field : field;
var subCondition;
if(con instanceof Array) {
subCondition = field + " " + con[0] + " " + wrapString(con[1]);
}else{
subCondition = field + " = " + wrapString(con);
}
conditionArray.push(subCondition);
}
}
return conditionArray.length > 0 ? conditionArray.join(" AND ") : "1";
}
//wrap string value
function wrapString(value){
return typeof value === "string" ? "'" + value + "'" : value;
}
So is there any way I can fix this problem?
Update
Thanks to Jordan's Offer, it's working, but :
I know building query by string concat is very good, but in my case I can't use that, because I'm using some middleware or handle mysql and controller, so what I can do is to define interface, which is a sql string with placeholders. So, the interface string is predefined before, and I can't modify it during my controller function.
You're off to a really good start, but you may have been overthinking it a bit. The trick is to build a query with placeholders (?) as a string and simultaneously build an array of values.
So, if you have params = { name: 'foo', age: 40 }, you want to build the following objects:
where = 'name LIKE ? AND age = ?';
values = [ '%foo%', 40 ];
If you only have { name: 'foo' }, you'll build these instead:
where = 'name LIKE ?';
values = [ '%foo%' ];
Either way, you can use those objects directly in the query method, i.e.:
var sql = 'SELECT * FROM table WHERE ' + where;
connection.query(sql, values, function...);
How do we build those objects, then? In fact, the code is really similar to your buildQuery function, but less complex.
function buildConditions(params) {
var conditions = [];
var values = [];
var conditionsStr;
if (typeof params.name !== 'undefined') {
conditions.push("name LIKE ?");
values.push("%" + params.name + "%");
}
if (typeof params.age !== 'undefined') {
conditions.push("age = ?");
values.push(parseInt(params.age));
}
return {
where: conditions.length ?
conditions.join(' AND ') : '1',
values: values
};
}
var conditions = buildConditions(params);
var sql = 'SELECT * FROM table WHERE ' + conditions.where;
connection.query(sql, conditions.values, function(err, results) {
// do things
});
For Inserting into MYSQL like DB:
function generateInsertQuery(data, tableName) {
let part1 = `INSERT INTO ${tableName} (`;
let part2 = ")",
part3 = "VALUES (",
part4 = ")";
let tableKeys = "",
tableValues = "";
for (let key in data) {
tableKeys += `${key},`;
tableValues += `'${data[key]}',`
}
tableKeys = tableKeys.slice(0, -1);
tableValues = tableValues.slice(0, -1);
let query = `${part1}${tableKeys}${part2} ${part3}${tableValues}${part4}`;
return query;
}
generateInsertQuery({name: "Sam", tel: 09090909, email: "address#domain.com"}, "Person")
Output:
INSERT INTO Person (name,tel,email) VALUES ('Sam','9090909','address#domain.com');
Code Snippet for Update query:
function generateUpdateQuery(data, tableName, clauseKey, clauseValue) {
let part1 = `UPDATE ${tableName} SET`;
let part2 = `WHERE ${clauseKey} = ${clauseValue};`; //Add any number of filter clause statements here
let updateString = "";
for (let key in data) {
updateString += `${key} = '${data[key]}',`;
}
updateString = updateString.slice(0, -1);
let query = `${part1} ${updateString} ${part2}`;
return query;
}
generateUpdateQuery({
name: "Tanjiro",
tel: 77777777,
email: "tanjiro#demonslayer.com"
}, "Person", "ID", 111);
Output:
UPDATE Person SET name = 'Tanjiro',tel = '77777777',email = 'tanjiro#demonslayer.com' WHERE ID = 111;
I modify your code #Jordan-Running
describe("Test generateFilterQuery", () => {
it("Query filter with params", () => {
let params = []
params.push(Query.generateParams("title", "%_%", "Coding"))
params.push(Query.generateParams("published", "=", true))
console.log(Query.generateFilterQuery(params))
});
});
const qInclude = require('./QueryInclude');
exports.generateParams = (name, eq, value) => {
return {
name: name,
eq: eq, // %_%, %_, _%, =, >, <, !=,
value: value
}
}
exports.generateFilterQuery = (params) => {
let conditions, values = []
let conditionsStr;
if (params.length == 0) {
return false
}
[conditions, values] = qInclude.queryCondition(params)
let build = {
where: conditions.length ?
conditions.join(' AND ') : '1',
values: values
};
let query = 'SELECT * FROM table WHERE ' + build.where;
return [query, build.values]
}
exports.queryCondition = (params) => {
var conditions = [];
var values = [];
params.forEach(item => {
switch (item.eq) {
case '=': {
conditions.push(item.name + " = ?");
values.push(item.value);
break;
}
case '!=': {
conditions.push(item.name + " != ?");
values.push(item.value);
break;
}
case '<': {
conditions.push(item.name + " < ?");
values.push(item.value);
break;
}
case '>': {
conditions.push(item.name + " > ?");
values.push(item.value);
break;
}
case '%_%': {
conditions.push(item.name + " LIKE ?");
values.push("%" + item.value + "%");
break;
}
case '%_': {
conditions.push(item.name + " LIKE ?");
values.push("%" + item.value);
break;
}
case '_%': {
conditions.push(item.name + " LIKE ?");
values.push(item.value + "%");
break;
}
}
});
return [conditions, values]
}

'INSERT INTO' does not insert data to my sql database

I used wamp server to browse the database , I started connection with database from nodejs express server
When I wrote insert query there is no error but when I browse the table the added row has empty values .
this is my query code
app.post('/new_sess_mouse',function(req,res ){
var sess_name = req.body.sess_name ,
sess_id = req.session.id ,
email = req.session.email ;
var sql = "INSERT INTO ?? SET ?? = ? AND ?? = ? AND ?? = ? ";
var inserts = ['sessions', 'sess_name' , sess_name ,'sess_id',sess_id ,'email' , email ];
sql = mysql.format(sql, inserts);
console.log(sql);
connection.query( sql , function( err , results ){
if(err) {
console.log(err.message);
}
else {
//connection.destroy();
console.log('succes');
}
}); });
When I printout the results
{ fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 3,
message: '',
protocol41: true,
changedRows: 0 }
You have wrong INSERT statement format.
You can :
var sql = "INSERT INTO ?? ( ??, ??, ??) VALUES (?, ?, ?)";
var inserts = ['sessions', 'sess_name' , 'sess_id', 'email', sess_name , sess_id , email ];
or:
var sql = "INSERT INTO ?? SET ?? = ? , ?? = ? , ?? = ? ";
var inserts = ['sessions', 'sess_name' , sess_name ,'sess_id',sess_id ,'email' , email ];