Good way to write sub queries in pg-promise - node.js

Incase I have to execute more queries in a single API in what method I have to proceed
Is this a better way to write sub queries inside main queries
without using db.task or db.tx or else I have to use these methods.
like this below
function userChangePassword(req, res) {
const changePwd = req.swagger.params.body.value;
const token = req.headers.authorization;
token.replace('Bearer ', '');
const decoded = jwt_decode(token);
const newpass = changePwd.newPassword;
const user_id = decoded.userId;
const userSel = `select * from xx."yy" where "userId" = '${user_id}' AND "status" = 1`;
const updatePwd = `update xx."yy" set "password" = '${newpass}' where "userId" = '${user_id}' `;
db.query(userSel).then((usrResult) => {
if (usrResult.length > 0) {
db.query(updatePwd).then(() => {
res.send(response.success("The password has been changed successfully", []));
});
} else {
res.send(response.success("The password has not changed successfully", []));
}
})
.catch((err) => {
if (util.isError(err)) res.error('NotFoundError', err); // return 404
else res.error('InternalServerError', err); // else 500
});
}
kindly help me to get solution for this confusion..
Thanks.

If you have a dependency between queries, then you have to use methods task/tx. Otherwise, you can concatenate queries into one, using helpers.concat, and execute them as one query, which will be faster. And you can use methods multi / multiResult, if you are expecting return data from your multi-query.

Related

"cannot insert multiple commands into a prepared statement" How do I return cursor results from a PostgreSQL Function in KOA service

I am using PostgreSQL FUNCTION to return result sets. I am having trouble getting my Node.js/KOA api to call it properly with parameters. I can get it to work without parameters, but the parameters turn it into a prepared statement. And the prepared statements don't like multiple commands.
Here is the database object and configuration that I use:
const { Pool } = require('pg');
const config = require('../configuration');
exports.pool = this.pool;
exports.start = async function() {
const host = config.get("PGHOST");
const user = config.get("PGUSER");
const port = config.get("PGPORT");
const password = config.get("PGPASSWORD");
const database = config.get("PGDATABASE");
this.pool = new Pool({ user, host, database, password, port });
console.log('Postgres database pool started.');
};
exports.close = async function() {
await this.pool.end;
};
exports.query = async function(query, data) {
let rs = await this.pool.query(query, data);
return rs;
};
Here is my KOA service (it uses the pg.Pool node module, and where my issue is, i think...):
let getFilteredDevelopers = async (developerId, firstName, lastName) => {
let query = {
text: `
BEGIN;
SELECT ks_get_filtered_developers($1, $2, $3);
FETCH ALL IN "ks_developers_cursor";
COMMIT;
`,
values: [ developerId, firstName, lastName ]
};
try {
let result = await database.query(query);
return result[2].rows;
} catch (error) {
return `Failed to fetch developers.`;
}
};
This approach works fine without the parameters. But when I add the parameters to the koa pg call, it throws the error: 'cannot insert multiple commands into a prepared statement'.
The following is my function:
CREATE OR REPLACE FUNCTION ks_get_filtered_developers (
p_developer_id NUMERIC,
p_first_name TEXT,
p_last_name TEXT
) RETURNS refcursor AS
$$
DECLARE
v_query TEXT = '';
v_where_clause TEXT = '';
v_developers_cursor refcursor = 'ks_developers_cursor';
BEGIN
IF (p_developer_id IS NOT NULL) THEN
v_where_clause = v_where_clause || FORMAT(' AND d.developer_id = %s ', p_developer_id);
END IF;
v_query = '
SELECT d.developer_id AS id, d.*
FROM ks_developers d
WHERE 1=1
' || v_where_clause || '
ORDER BY d.developer_id
';
OPEN v_developers_cursor FOR
EXECUTE v_query;
RETURN v_developers_cursor;
END;
$$
LANGUAGE plpgsql;
How can I implement this in the appropriate way? What am I missing or misunderstanding?
The problem was my lack of understanding on how to use the pg node module. Basically, I was trying to jam everything into one query, because I thought I had to. I forgot that I created a "helper" query in the database module, and that it was narrow. I got that confused with the pg pool query function name. I was shooting myself in the foot.
This is the article that showed me how multiple statements should be done with a transaction:
https://node-postgres.com/features/transactions
So for a quick fix on this question, I exposed the pool to myself and started querying the pool, and then released the connection. This allows for multiple prepared statements and actions.
Here is what I modified my koa to be:
let getFilteredDevelopers = async (developerId, firstName, lastName) => {
const client = await database.pool.connect();
try {
await client.query('BEGIN');
const selectQuery = `SELECT ks_get_filtered_developers($1, $2, $3)`;
await client.query(selectQuery, [ developerId, firstName, lastName ]);
const fetchQuery = `FETCH ALL IN "ks_developers_cursor"`;
const result = await client.query(fetchQuery);
client.query('COMMIT');
return result.rows;
} catch (error) {
client.query('ROLLBACK');
return `Failed to fetch developers.`;
} finally {
client.release();
}
};
I will be refactoring my code to handle this better, but I wanted to answer the question of why this code doesn't work, and what I was misunderstanding.

Getting Error [Cannot read properties of undefined (reading 'generatetypeinfo')] in Node JS API post method

I am new to Restful API development using NodeJS and SQL Server. I am trying to do a simple [post] operation where I am passing an array of objects to the API endpoint and then calling a SQL Server procedure with a table valued parameter. I am getting the below error
Cannot read properties of undefined (reading 'generateTypeInfo')
I was really shocked to see that there is not a single help topic found over Google regarding this error. I do not want to learn ASP.NET Core for this because JavaScript has an easy learning curve. Am I doing a mistake by developing a Rest API by using the combination of NodeJS and SQL Server? Below is my Related .JS file called in Post endpoint
const sql = require("mssql/msnodesqlv8");
const dataAccess = require("../DataAccess");
const fn_CreateProd = async function (product) {
let errmsg = "";
let connPool = null;
await sql
.connect(global.config)
.then((pool) => {
global.connPool = pool;
result = pool.request().query("select * from products where 1=2");
return result;
})
.then((retResult) => {
const srcTable = retResult.recordset.toTable("tvp_products");
let newsrcTable = Array.from(srcTable.columns);
console.log('Source table b4 mapping',srcTable)
newsrcTable = newsrcTable.map((i) => {
i.name = i.name.toUpperCase();
return i;
});
console.log('Source table after convert array with mapping',newsrcTable)
const prdTable = dataAccess.generateTable(
newsrcTable,
product,
"tvp_products"
);
console.log("Prepared TVp data", prdTable);
const newResult = dataAccess.execute(`sp3s_ins_products_tvp`, [
{ name: "tblprods", value: prdTable },
]);
console.log("Result of Execute Final procedure", newResult);
return newResult;
})
.then(result => {
console.log("Result of proc", result);
if (!result.errmsg) errmsg = "Products Inserted successfully";
else errmsg = result.errmsg;
})
.catch((err) => {
console.log("Enter catch of Posting prod", err.message);
errmsg = err.message;
})
.finally((resp) => {
sql.close();
});
return { retStatus: errmsg };
};
module.exports = fn_CreateProd;
and Content of Generatetable function are as below :
const generateTable = (columns, entities,tvpName) => {
const table = new mssql.Table(tvpName);
// const testobj = {type : [sql.numeric],name : 'Sanjay'}
// console.log('Columns testobj',testobj.type)
columns.forEach(column => {
// console.log('COlumn data for COlumn :',column)
if (column && typeof column === 'object' && column.name && column.type) {
let colOptions = {}
if (column.type==mssql.Numeric)
{
colOptions.scale=column.scale
colOptions.precision=column.precision
}
else
if (column.type==mssql.VarChar || column.type==mssql.Char )
{
colOptions.length = column.length
}
// console.log (`Column name type for column :${column.name} -${colType}-Actual :${column['type']}`)
if (column.hasOwnProperty('options')) {
table.columns.add(column.name.toUpperCase(), colType,column.options);
} else {
table.columns.add(column.name.toUpperCase(),colOptions)
}
}
});
console.log('Generated table',table)
const newEntities = entities.map(obj=>keystoUppercase(obj))
// console.log('New entities after uppercase',newEntities)
newEntities.forEach(entity => {
table.rows.add(...columns.map(i =>
entity[i.name]));
});
return table;
};
I have found the solution now. Actually, if you can see the code of generateTable function, I was adding the columns into the table but not mentioning the data type of the columns due to which this error was coming. I have added one more property [type] in the [colOptions] object being passed to columns.add command in the function [Generatetable]. Thanks a lot anyway to you for quick replies by Dale. K.

Request Body Read Multiple Value on Node Js

i am new in NodeJs development,
i want to ask, surely this is kinda basic, but i dont know how to do it.
i have a task to read request one field that can filled with multiple values,
on json array like this :
{
"email" : "first#mail.com" , "second#mail.com", "third#mail.com"
}
how to get each value from that "email" field and processing it to some function ?
i have a query select to get username from one table
select username from [dbo].[users] where email=#email (first, second, and third)
this is my code for now only that read one value, not multiple :
async getValueFunction(req, res) {
res.setHeader('Content-Type', 'application/json');
try {
if (req.body.email != "") {
const pool = await poolPromise
const result = await pool.request()
.input('email', sql.VarChar, req.body.email)
.query(queries.getUserScoreByEmail)
var showUserScore = result.recordset;
res.json(showUserScore);
} else if (req.body.email == "") {
const pool = await poolPromise
const result = await pool.request()
.query(queries.getUserScore)
var showAllUserScore = result.recordset;
res.json(showAllUserScore);
}
} catch (error) {
res.status(500)
res.send(error.message)
}
}
how to do the loop (iteration) and collect the result/recordset before send as one response (json) ??
You should update your structure because it is not an key value pair.
What you can do is storing the E-Mail Adresses in an Array like this
const data ={
"email" : ["first#mail.com" , "second#mail.com", "third#mail.com" ]
}
And then you access it with data.email

How to correctly make multiple MySQL calls in a single request with Node.js, Express.js, MySQL2, and Promises

Looking at the correct/best/better way to use AWAIT with MySQL2 in a Node.js/Express.js app when I need to run multiple queries in a single request.
Early on in my app I create a Promise Pool from my Database config
const promisePool = db.promise();
Then, on a POST request I accept 2 values, both of which I need to verify are valid, and then take the returned ID's and INSERT them in to another table.
Below is was my first attempt but I am missing out on the JS's concurrently goodness. (I've overly simplified all the calls/SQL for demonstration purposes),
app.post('/addUserToDepartment', async (req, res) => {
// Get the POST variables
let email = 'example#example.com';
let departmentname = 'sales';
let insertParams = [];
// Need to check if Department ID is even valid
const [departments] = await promisePool.query( "SELECT ? AS deptid", [departmentname] );
// Need to check if Email address is valid
const [user] = await promisePool.query( "SELECT ? AS userid", [email] );
// This would normall be an INSERT or UPDATE statement
if(departments.length && user.length){
const [rows] = await promisePool.query( "SELECT ? AS passedDeptId,? AS passedUserid", [departments[0].deptid, user[0].userid] );
}
res.send( rows )
}
Here is my second stab at it, now wrapping the promises up.
app.post('/addUserToDepartment', async (req, res) => {
// Get the POST variables
let email = 'example#example.com';
let departmentname = 'sales';
let insertParams = [];
// Need to check if Department ID is even valid
let [[departments],[user]] =
await Promise.all([
promisePool.query( "SELECT ? AS deptid", [departmentname] ),
promisePool.query( "SELECT ? AS userid", [email] )
])
// This would normall be an INSERT or UPDATE statement
if(departments.length && user.length){
let [rows] = await promisePool.query( "SELECT ? AS passedDeptId,? AS passedUserid", [departments[0].deptid, user[0].userid] );
}
res.send( rows )
}
The IF at the end still doesn't 'feel' right, but I need to know that the first two queries are valid otherwise I'll send the user to an error page.
What would be a better way to achieve the above result without forfeiting readability too much?
first: both snippets are broken as the rows variable needs to be declared outside if if.
Aside from that, what you're doing is mostly fine, but the big issue here is that if length of either is 0, you return nothing.
Is that really the behavior you want? If I call /addUserToDepartment and there is a problem in your database, do you want this to silently fail?
I think a better approach is to return appropriate errors when something goes wrong. Ideally you should just throw an exception, (but you're using Express, and I'm not sure if they support catching exceptions).
Here is what I went with in the end. I added catches, I also did my last query as a part of the Promise.all() chain.
app.get('/test2', async (req, res) => {
// Get the POST variables
let email = 'example#example.com';
let departmentname = 'sales';
let insertParams = [];
let rtn = {
status : '',
errors : [],
values : []
}
console.clear();
// Need to check if Department ID is even valid
let arrayOfPromises = [
promisePool.query( "SELECT ? AS did", [departmentname] ),
promisePool.query( "SELECT ? AS uid", [email] )
]
await Promise.all(arrayOfPromises)
.then( ([d,u] ) => {
// Get the values back from the queries
let did = d[0][0].did;
let uid = u[0][0].uid;
let arrayOfValues = [did,uid];
// Check the values
if(did == 'sales'){
rtn.values.push( did );
} else{
rtn.errors.push( `${did} is not a valid department`);
}
if(uid == 'example#example.com'){
rtn.values.push( uid );
} else{
rtn.errors.push( `${did} is not a valid department`);
}
if( rtn.errors.length === 0){
return arrayOfValues;
} else{
return Promise.reject();
}
})
.then( async ( val ) => {
// By this point everything is ok
let [rows] = await promisePool.query( "SELECT ? AS passedDeptId,? AS passedUserid", val );
res.send( rtn )
})
.catch((err) => {
console.error(err)
rtn.status = 'APPLICATION ERROR';
rtn.errors.push( err.message);
res.send( rtn )
});
});

Node.js Query sqlite with 'sqlite`

I'm trying to get a hang of Node (I mainly use python) so I'm working on a small project to read an write data to a sqlite database.
I am having no issue writing to the database luckily, but I cannot seem to get queries to work at all. I've tested the queries in the sql terminal and they are successful.
So far, I have something like
const fs = require("fs");
const util = require("util");
const sqlite = require("sqlite");
const Promise = require("bluebird")
// const DATABASE = ":memory:";
const DATABASE = "./database.sqlite";
function insertDataIntoDatabase(transactions, db) {
// Write each transaction into the database.
let sqlStatement = "INSERT INTO Trx \
(name, address, amount, category) \
VALUES "
for (var i = 0; i < transactions.length; ++i) {
let trx = transactions[i];
sqlStatement += util.format(
"('%s', '%s', %d, '%s'), ",
trx.name,
trx.address,
trx.amount,
trx.category,
);
}
sqlStatement = sqlStatement.substring(0, sqlStatement.length - 2);
db.then(db => db.run(sqlStatement))
.catch((err) => console.log(err));
}
function getTransactions (db, category) {
// Return an array of valid transactions of a given category.
let where = "";
if (category) {
where = util.format("WHERE category='%s'", category);
}
let sqlStatement = util.format("SELECT * from Trx %s", where);
sqlStatement = "SELECT * from Trx"; // Trying to figure out whats happening
console.log(sqlStatement);
db.then(db => {
db.all(sqlStatement)
.then((err, rows) => {
console.log(rows); // undefined
console.log(err); // []
})
})
}
// Set up the db connection
const db = sqlite.open(DATABASE, { cached: true })
.then(db => db.migrate({ force: 'last' }));
// Read transactions and write them to the database
fs.readFile("transactions.json", "utf8", (err, data) => {
let transactions = JSON.parse(data).transactions;
insertDataIntoDatabase(transactions, db);
})
// Get transaction data
getValidTransactions(db, 'credit');
// Close connection to DB
db.then(db => db.close());
Looking at this again, I think the issue is the async nature of Node. The query was successful, but at that point in time, I had not inserted the data from the json file into the database yet, hence the empty query.

Resources