Management dates on sql server with node.js - sql

the code below performs a select on a sql server database, when the code is executed the following error is generated, i have this error: TypeError: parameter.value.getTime is not a function
Input Parameter:
IdUtente=2
dataInizio=01-07-2018
datafine=02-09-2018
Date:
01-08-2018
01-10-2018
01-11-2018
02-01-2019
02-08-2018
JavaScript:
async function CaricaDataeTotaleOre(IdUtente,dataInizio,datafine) {
console.log("Carica Data e Totale Ore -- IdUtente: "+IdUtente+"\n Data Inizio: "+dataInizio+"\n Data Fine: "+datafine);
var data = [];
var query = "SET LANGUAGE 'Italian' SELECT Distinct CONVERT(varchar(10), DataCreazione, 105) as Data FROM Marcatura inner join Utente on Utente.IdUtente = Marcatura.IdUtente where Utente.IdUtente = #IdUtente and(CONVERT(VARCHAR(10),Marcatura.DataCreazione,103) between #Start and #End) ";
const ret = await new Promise((resolve, reject) => {
new sql.ConnectionPool(DbConfig.config).connect().then(pool => {
return pool.request().input('IdUtente', sql.Int, IdUtente).input('Start', sql.DateTime, dataInizio).input('End', sql.DateTime, datafine).query(query)
}).then(result => {
resolve(result);
sql.close();
}).catch(err => {
ManageError.SendError("Errore CaricaDataeTotaleOre con : " + IdUtente + "\n Errore: " + err);
reject(err)
sql.close();
});
});
for (var i = 0; i < ret.recordset.length; i++) {
data.push({
Data: ret.recordset[i].Data
})
}
return data;
}

Related

Node.JS Oracle Patch Request not dynamic

I'm trying to dynamically make a patch request for oracle tables through Node.JS
Here's my setup:
In my router.js file I have this:
const express = require('express');
const router = new express.Router();
const employees = require('../controllers/employees.js');
const smiCats = require('../controllers/smi/smiCats.js');
const auth = require('../controllers/auth.js');
router.route('/login/:id?')
.post(auth.getToken);
router.route('/ams/:id?')
.get(auth.verifyToken, employees.get)
.post(auth.verifyToken, employees.post)
.put(auth.verifyToken, employees.put)
.delete(auth.verifyToken, employees.delete)
.patch(auth.verifyToken, employees.patch);
router.route('/smi/cats/:id?')
.get(auth.verifyToken, smiCats.get)
.post(auth.verifyToken, smiCats.post)
.put(auth.verifyToken, smiCats.put)
.patch(auth.verifyToken, smiCats.patch);
module.exports = router;
That then calls my controller that has my patch function & gets sanitized.
//sanitizer
function sanitizeCats(req) {
const cats = {
cat_desc: req.body.cat_desc,
msg_for: req.body.msg_for,
msg_user_owner: req.body.msg_user_owner || 0,
msg_realtor_owner: req.body.msg_realtor_owner || 0
};
return cats;
}
async function patch(req, res, next) {
try {
let category = sanitizeCats(req);
category.cat_id = parseInt(req.params.id, 10);
const success = await smiCats.patch(category);
if (success) {
res.status(204).end();
} else {
res.status(404).end();
}
} catch (err) {
next(err);
}
}
module.exports.patch = patch;
When that gets executed it calls my db_api module, which assembles the sql statement
(THE NEXT CODE SECTION IS WHERE MY QUESTION COMES FROM)
const database = require('../../services/database.js');
const oracledb = require('oracledb');
const patchSql =
`BEGIN
DECLARE
BEGIN
IF nvl(:cat_desc,'zzz') != 'zzz' THEN
UPDATE smi_contact_cats
SET cat_desc = :cat_desc
WHERE cat_id = :cat_id;
END IF;
IF nvl(:msg_for,'zzz') != 'zzz' THEN
UPDATE smi_contact_cats
SET msg_for = :msg_for
WHERE cat_id = :cat_id;
END IF;
IF nvl(:msg_user_owner,-1) > -1 THEN
UPDATE smi_contact_cats
SET msg_user_owner = :msg_user_owner
WHERE cat_id = :cat_id;
END IF;
IF nvl(:msg_realtor_owner,-1) > -1 THEN
UPDATE smi_contact_cats
SET msg_realtor_owner = :msg_realtor_owner
WHERE cat_id = :cat_id;
END IF;
:rowcount := sql%rowcount;
END;
END;`;
async function patch(cats) {
const category = Object.assign({}, cats);
//add binds
category.rowcount = {
dir: oracledb.BIND_OUT,
type: oracledb.NUMBER
};
const result = await database.simpleExecute(patchSql, category);
return result.outBinds.rowcount === 1;
}
module.exports.patch = patch;
This then calls the database function to actually execute & assemble the sql with the bind variables:
const oracledb = require('oracledb');
const dbConfig = require('../config/database.js');
async function initialize() {
const pool = await oracledb.createPool(dbConfig.beta);
}
module.exports.initialize = initialize;
async function close() {
await oracledb.getPool().close();
}
module.exports.close = close;
function simpleExecute(statement, binds = [], opts = {}) {
return new Promise(async (resolve, reject) => {
let conn;
opts.outFormat = oracledb.OBJECT;
opts.autoCommit = true;
try {
conn = await oracledb.getConnection();
const result = await conn.execute(statement, binds, opts);
resolve(result);
} catch (err) {
reject(err);
} finally {
if (conn) { // conn assignment worked, need to close
try {
await conn.close();
} catch (err) {
console.log(err);
}
}
}
});
}
module.exports.simpleExecute = simpleExecute;
So all of this works... but it's not dynamic enough for me to build our company api. How do I make a more dynamic patch request in Node.JS without having to type out every single column & put an nvl around it to check if it's there. As a side not if there's a better way to dynamically sanitize as well, I'm all ears, but the main question is on how to dynamically build the patch request better.
The current code is suboptimal in that is does one update per property. Here's a more dynamic solution...
Given the following:
create table smi_contact_cats (
cat_id number,
cat_desc varchar2(50),
msg_for varchar2(50),
msg_user_owner varchar2(50),
msg_realtor_owner varchar2(50)
);
insert into smi_contact_cats (
cat_id,
cat_desc,
msg_for,
msg_user_owner,
msg_realtor_owner
) values (
1,
'cat_desc orginal value',
'msg_for orginal value',
'msg_user_owner orginal value',
'msg_realtor_owner orginal value'
);
commit;
You can use logic like this. updatableColumns is the whitelist of columns that can be updated. Note that you can comment and uncomment some of the lines toward the bottom to test various input.
const oracledb = require('oracledb');
const config = require('./db-config.js');
async function patch(cat) {
let conn;
try {
const category = Object.assign({}, cat);
const categoryProps = Object.getOwnPropertyNames(category);
const updatableColumns = ['cat_desc', 'msg_for', 'msg_user_owner'];
// Validate that the pk was passed in
if (!categoryProps.includes('cat_id')) {
throw new Error('cat_id is required');
}
// Now remove the pk col from categoryProps
categoryProps.splice(categoryProps.indexOf('cat_id'), 1);
if (categoryProps.length === 0) {
throw new Error('At least one property must be specified');
}
let sql = 'update smi_contact_cats\nset ';
for (let propIdx = 0; propIdx < categoryProps.length; propIdx++) {
// Here's the whitelist check
if (!updatableColumns.includes(categoryProps[propIdx])) {
throw new Error('Invalid "update" column');
} else {
if (propIdx > 0 && propIdx < categoryProps.length) {
sql += ',\n ';
}
sql += categoryProps[propIdx] + ' = :' + categoryProps[propIdx];
}
}
sql += '\nwhere cat_id = :cat_id';
console.log('here is the sql', sql);
conn = await oracledb.getConnection(config);
const result = await conn.execute(
sql,
category,
{
autoCommit: true
}
);
if (result.rowsAffected && result.rowsAffected === 1) {
return category;
} else {
return null;
}
} catch (err) {
console.error(err);
} finally {
if (conn) {
try {
await conn.close();
} catch (err) {
console.error(err);
}
}
}
}
const patchObj = {
cat_id: 1
};
// Comment and uncomment the following to see various dynamic statements
patchObj.cat_desc = 'cat_desc value';
patchObj.msg_for = 'msg_for value';
patchObj.msg_user_owner = 'msg_user_owner value';
// Uncomment the following line to add a column that's not whitelisted
//patchObj.msg_realtor_owner = 'msg_realtor_owner value';
patch(patchObj)
.then(function(cat) {
console.log('Updated succeeded', cat);
})
.catch(function(err) {
console.log(err);
});

Reading from one db into another

I am trying to right a function that copies some fields from several company databases into my own database once a day. What I have so far is below. I am wondering if where I console.log(rs) I can open another sql connection to my database and write the data or if I have to store the results somewhere and then open a new connection and send the stored results.
function updateJobs() {
var query = "SELECT JobStart, JobEnd FROM JobData";
sql.connect(Config, (err) => {
if (err) {
console.log("Error while connecting database :- " + err);
} else {
var request = new sql.Request();
request.query(query, function (err, rs) {
if (err) {
console.log("Error while querying database :- " + err);
sql.close();
} else {
console.log(rs);
sql.close();
}
})
}
})
}
This might help
// Source Database
sourceDB.each(`select * from ${Sourcetable}`, (error, row) => {
console.log(row);
const keys = Object.keys(row); // ['columnA', 'columnB']
const columns = keys.toString(); // 'columnA,columnB'
let parameters = {};
let values = '';
// Generate values and named parameters
Object.keys(row).forEach((r) => {
var key = '$' + r;
// Generates '$columnA,$columnB'
values = values.concat(',', key);
// Generates { $columnA: 'ABC', $columnB: 'GHK' }
parameters[key] = row[r];
});
// Insert into another database into OneTable (columnA,columnB) values ($columnA,$columnB)
// Parameters: { $columnA: 'ABC', $columnB: 'GHK' }
destDB.run(`insert into ${Desttable} (${columns}) values (${values})`, parameters);
})
})

Writing data from txt file to database in node js

I read data from a text file:
const byline = require('byline');
const fs = require('fs');
var stream = byline(fs.createReadStream('C:/Users/../test.txt'));
var index = 0;
var headers;
var data = [];
stream.on('data', function(line) {
var currentData;
var entry;
var i;
line = line.toString(); // Convert the buffer stream to a string line
//line = Buffer.from(line, 'latin1').toString();
if (index === 0) {
headers = line.split(/[ ]+/);
} else {
currentData = line.split(/[ ]+/);
entry = {};
for (i = 0; i < headers.length; i++) {
entry[headers[i]] = currentData[i];
}
data.push(entry);
}
index++;
});
stream.on("error", function(err) {
console.log(err);
});
stream.on("end", function() {
console.log(data);
console.log("Done");
});
That works just fine. So now i am trying to write this into a my database. Therefore i implemented this part at the end of the stream, when all of the data has been read.
stream.on("end", function() {
console.log(data);
console.log("Done");
for(h = 0; h < data.length; h++){
let name = data[h].Name;
let id = data[h].ID;
let text = data[h].Text;
let text1 = data[h].Text1;
let text2 = data[h].Text2;
let text3 = data[h].Text3;
Conn.query('INSERT INTO Config SET ? ', { Name: name, ID: id, Text: text, Text1: text1, Text2: text2, Text3: text3}, function (error, result, fields) {
if (error) throw error;
});
}
return res.send({ error: false, data: result, message: 'New configuration has been created.' });
});
But it seems like this does not work. What am i missing?
You can try the following
stream.on("end", function() {
console.log(data);
console.log("Done");
var promises = [];
for (h = 0; h < data.length; h++) {
let name = data[h].Name;
let id = data[h].ID;
let text = data[h].Text;
let text1 = data[h].Text1;
let text2 = data[h].Text2;
let text3 = data[h].Text3;
promises.push(new Promise(function insertIntoDatabase(resolve, reject) {
Conn.query('INSERT INTO Config SET ? ', {
Name: name,
ID: id,
Text: text,
Text1: text1,
Text2: text2,
Text3: text3
}, function(error, result, fields) {
if (error) reject(error);
else resolve();
})
}));
}
Promise.all(promises)
.then(function(data) {
res.send({
error: false,
data: result,
message: 'New configuration has been created.'
});
})
.catch(function(err) {
console.log("Error occured due to : ", err);
res.send({
error: true,
data: null,
message: 'Error during config'
});
});
//It is a bad practise to have a async operation that can throw error inside a synchronous loop
/*
for(h = 0; h < data.length; h++){
let name = data[h].Name;
let id = data[h].ID;
let text = data[h].Text;
let text1 = data[h].Text1;
let text2 = data[h].Text2;
let text3 = data[h].Text3;
Conn.query('INSERT INTO Config SET ? ', { Name: name, ID: id, Text: text, Text1: text1, Text2: text2, Text3: text3}, function (error, result, fields) {
if (error) throw error;
});
}
*/
});

SQL query with async each

My problem is when I am getting array of users and trying to run async each it start each sqlRequest and not going one by one pushing in array.
It should do sqlRequest 1 by 1, and not do all by each user sqlRequest and the push in an array.
Here is a async each
function getUserFavCat(params, callback) {
var usersArrayCat = [];
async.each(params, function (user, cb) {
sqlRequest("SELECT b_cat.title, b_cat.id FROM dbo.Students st INNER JOIN dbo.SaleView sv ON sv.userId = st.id INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON b_key.saleId = sv.saleId INNER JOIN dbo.BrandCategories b_cat ON b_cat.id = b_key.brandCategoryId WHERE st.id = " + user.id, function (err, result) {
if (!result) {
//console.error("NO FAVOURITE CATEGORY FOR USER " + JSON.stringify(user))
} else if (result.length == 0) {
//console.error("NO FAVOURITE CATEGORY FOR USER " + JSON.stringify(user))
} else {
user.favouriteCat = utils.takeMostRepeatingObj(result);
usersArrayCat.push(user);
}
cb();
})
}, function() {
callback(null, usersArrayCat)
});
};
Here is the SQL query:
function sqlRequest (sqlQuery, callback) {
var connection = new sql.Connection(sql_conf, function (err) {
if (err){
console.log(err)
} else {
var request = new sql.Request(connection);
request.query(sqlQuery, function(err, result) {
console.log(result)
if(err){
console.error(err)
} else if(!result){
console.error("NO RESPONSE SQL QUERY")
} else {
callback(null, result);
connection.close();
}
})
}
});
connection.on('error', function(err) {
console.log(err);
});
};
use async.eachLimit to limit the no. of request
function getUserFavCat(params, callback) {
var usersArrayCat = [];
console.log(`length of array ${params.length}`)
// 1 here means 1 request at a time
async.eachLimit(params, 1, function (user, cb) {
sqlRequest("SELECT b_cat.title, b_cat.id FROM dbo.Students st INNER JOIN dbo.SaleView sv ON sv.userId = st.id INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON b_key.saleId = sv.saleId INNER JOIN dbo.BrandCategories b_cat ON b_cat.id = b_key.brandCategoryId WHERE st.id = " + user.id, function (err, result) {
if (!result) {
//console.error("NO FAVOURITE CATEGORY FOR USER " + JSON.stringify(user))
} else if (result.length == 0) {
//console.error("NO FAVOURITE CATEGORY FOR USER " + JSON.stringify(user))
} else {
user.favouriteCat = utils.takeMostRepeatingObj(result);
usersArrayCat.push(user);
cb();
}
})
}, function (err) {
if (err) return callback(err);
callback(null, usersArrayCat)
});
};
Try this trick by using async.map and push for every callback to an array. Then you can use async.parallel to filter out the callback results for the success user and push it to usersArrayCat arrays
function getUserFavCat(params, callback) {
var usersArrayCat = [], callbackArrays = [];
async.map(params, function (user, cb) {
callbackArrays.push(function (cb) {
sqlRequest("SELECT b_cat.title, b_cat.id FROM dbo.Students st INNER JOIN dbo.SaleView sv ON sv.userId = st.id INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON b_key.saleId = sv.saleId INNER JOIN dbo.BrandCategories b_cat ON b_cat.id = b_key.brandCategoryId WHERE st.id = " + user.id, function (err, result) {
if (!result) {
user.status = '99'; // error status
cb(null, user);
} else if (result.length == 0) {
user.status = '99'; // error status
cb(null, user);
} else {
user.favouriteCat = utils.takeMostRepeatingObj(result);
user.status = '00'; //success status
cb(null, user);
}
});
}, function(err, results) {
// comes here after all individual async calls have completed
// check errors; array of results is in data
cb(null, results)
});
async.parallel(callbackArrays, function (err, results) {
results.forEach (function (elem, ind) {
if (elem.status == '00') {
usersArrayCat.push(elem);
}
});
});
};

SQL tedious add array as parameter

I'm running this SQL query with tedious.js using parameters:
var query = "select * from table_name where id in (#ids)";
request = new sql.Request(query, function(err, rowCount) {
if (err) {
}
});
request.on('row', function(columns) {
});
var id = [1, 2, 3];
request.addParameters('ids', TYPES.Int, id);
connection.execSql(request);
because I am looking for items that matches the ID provided with where ... in ... clause, I need to pass in an array. However, there is no TYPES.Array. How do I this properly?
for this query, i think you'll just have to manually build the entire sql string. the TYPES enum values are for the datatypes in the database, not in your JavaScript code.
//you can like this:
var userIds = result.map(function (el) {
return el.UserId;
}).join(',');
var params = [{
name: 'userIds',
type: TYPES.VarChar,
value: userIds,
options: null}];
var querySql = ['SELECT COUNT([MomentId]) FROM [T_Moment]',
'WHERE [RecordStatus] = ', sysConst.recordStatus.activation, " AND CHARINDEX(','+RTRIM([UserId])+',' , ','+ #userIds +',')>0 "].join(' ');
dbHelper.count(querySql, params, function (err, result) {
if (err) {
callback('error--');
} else {
callback(null, result);
}
});
Try creating the in clause parameters for query dynamically.
// create connection
let ids = [1, 2, 3];
let inClauseParamters = createInClauseParameters();
let query = `select * from table_name where id in (${inClauseParamters})`;
let request = new Request(query, (err, rowCount) => {
if (err) { /* handle error */ }
});
request.on('row', (columns) => { /* get row */});
request = addRequestParameters(ids, request);
connection.execSql(request);
function createInClauseParameters(values) {
return values.map((val, index) => `#Value${index}`).join(',');
}
function addRequestParameters(values, request) {
values.forEach((val, index) => {
request.addParameter(`Value${index}`, TYPES.VarChar, val);
});
return request;
}