NodeJs: `beginTransaction` is not a function error in mysql2 - javascript

In my below code, I am getting the error is not a function. This error is thrown in the line await con.promise().beginTransaction(); please check my code below.
const mysql = require('mysql2');
const errorCodes = require('source/error-codes');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
const con = mysql.createPool({
connectionLimit : 10,
host: prop.get('server.host'),
user: prop.get("server.username"),
password: prop.get("server.password"),
port: prop.get("server.port"),
database: prop.get("server.dbname")
});
exports.checkInvestorBoost = async (event, context) => {
context.callbackWaitsForEmptyEventLoop = false;
con.config.namedPlaceholders = true;
const params = event.queryStringParameters;
if (!params || params.iduser == null) {
var response = errorCodes.not_null_parameters;
return response;
} else {
if(isNaN(params.iduser))
{
var response = errorCodes.missing_fields;
return response;
}
const iduser = Number(params.iduser);
const toDate = new Date();
console.log("iduser: " + iduser);
let sql = "SELECT * FROM golden_circle_member WHERE iduser= :iduser AND is_investor_boost = true AND to_date > :to_date";
try {
await con.promise().beginTransaction();
const [data, meta] = await con.promise().query(sql, {
iduser: iduser,
to_date: toDate
});
// commit and complete
await con.promise().commit();
let output= false;
if(data.length>0)
{
output = true;
}
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify({
"is_investor_boost": output
}),
"isBase64Encoded": false
};
return response;
} catch (error) {
console.log(error);
var response = errorCodes.internal_server_error;
return response;
}
}
};
Reading about the question, I figured out that when createPool is used, I need to get the connection first. Not sure how I can get that done. Plus, I prefer to do this with async/await
Appreciate your advice here

This should work:
const mysql = require('mysql2/promise');
…
const pool = mysql.createPool(…);
const connection = await pool.getConnection();
try {
await connection.beginTransaction();
…
const [data, meta] = await connection.query(…);
…
await connection.commit();
} catch(err) {
await connection.rollback();
}
This also uses the mysql2 promise wrapper so you don't have to use .promise() each time.

You've to get the connection from the promise pool before starting a transaction.
const conn = await pool.promise().getConnection();
await conn.beginTransaction();

Related

Firestore : why using serverTimestamp gives different results?

I am having a hard time understanding serverTimestamp in firestore.
When I save a document in database in a firebase function using Fieldvalue.serverTimestamp() or in a javascript client code using serverTimestamp() it sometimes doesn't save the same thing in the database.
See screenshots below :
Sometime I get an object with {nanoseconds: xxx, seconds: xxx} and sometimes I get a timestamp formatted date...
The problem is when I try to query my orders using query(collectionRefOrders, orderBy('createdAt', 'desc'), limit(10)).
The orders with the object appears before the others ones even if they are created after...
Any clue why this happens ? What am I doing wrong ?
Thanks a lot.
EDIT :
Here is the code I use to add documents in the my firebase function (it is a request function I call in a website) :
const { getFirestore, FieldValue } = require('firebase-admin/firestore');
const firebaseDB = getFirestore();
exports.createOrderFromTunnel = functions.region('europe-west3')
.runWith({
timeoutSeconds: 10,
memory: "4GB",
})
.https
.onRequest(async (req, res) => {
cors(req, res, async () => {
try {
const { apiKey } = req.body;
const project = await getProjectFromApiKey(apiKey);
if (!project) {
return res.json({
success: false,
error: 'Unauthorized: invalid or missing api key'
});
}
const contactData = {
address: {},
createdAt: FieldValue.serverTimestamp()
};
const orderData = {
accounting: {
totalHT: 0,
totalTTC: 0,
totalTVA: 0,
},
createdAt: FieldValue.serverTimestamp(),
status: 'NEW',
};
const refProject = firebaseDB
.collection('projects')
.doc(project.id);
const colOrder = firebaseDB.collection(`projects/${project.id}/orders`)
const refOrder = colOrder.doc();
const colContact = firebaseDB.collection(`projects/${project.id}/contacts`)
const refContact = colContact.doc();
await firebaseDB.runTransaction(async transaction => {
const snapProject = await transaction.get(refProject);
const dataProject = snapProject.data();
const sequenceContact = dataProject.sequenceContact;
const sequenceOrder = dataProject.sequenceOrder;
contactData.sequence = sequenceContact;
orderData.sequenceNumber = sequenceOrder;
await transaction.set(refContact, contactData);
orderData.customer.id = refContact.id;
orderData.customer.sequence = sequenceContact;
await transaction.set(refOrder, orderData);
await transaction.update(refProject, {
sequenceContact: sequenceContact + 1,
sequenceOrder: sequenceOrder + 1,
totalContacts: dataProject.totalContacts + 1,
totalOrders: dataProject.totalOrders + 1,
});
return refOrder.id;
});
return res.json({
success: true
});
} catch (err) {
functions.logger.error(err);
return res.json({
success: false,
err
});
}
});
});
Here is the code I use to add documents in my client code (it is a web app in javascript) :
const createOrder = async (projectId) => {
try {
const orderData = {
accounting: {
totalHT: 0,
totalTTC: 0,
totalTVA: 0,
},
createdAt: serverTimestamp(),
status: 'NEW',
surface: 0,
};
const refProject = doc(firebaseDB, 'projects', projectId);
const colOrder = collection(firebaseDB, `projects/${projectId}/orders`)
const refOrder = doc(colOrder);
return await runTransaction(firebaseDB, async (transaction) => {
const snapProject = await transaction.get(refProject);
if (!snapProject.exists()) {
throw "Document does not exist!";
}
const dataProject = snapProject.data();
const sequence = dataProject.sequenceOrder;
orderData.sequenceNumber = sequence;
transaction.set(refOrder, orderData);
transaction.update(refProject, { sequenceOrder: sequence + 1, totalOrders: dataProject.totalOrders + 1 });
return refOrder.id;
});
} catch (e) {
console.error(e);
return null;
}
};

Node function not working, await part is not getting executed in the given function

While hitting API I'm getting function from my services/ElasticSearch.js and for some reason function there is not working after the axios part.
In the below file I've called function elasticService.updateDocument this function has been brought from another file.
'''
class ProductController {
constructor() { }
async saveProduct(req, res) {
console.log('ITs coming here')
let { _id, Product } = req.body;
if (_id) delete req.body._id;
let elasticResult;
try {
if (Product && Product.Category) {
req.body.Category = Product.Category
delete Product.Category
}
if (Product && Product.URL) {
const exists = await ProductService.checkProductByUrl(Product.URL);
_id = exists._id
}
const result = await ProductService.saveProduct(req.body, _id);
if (result) {
if (_id) {
console.log('Here.... UPDATE')
const savedProduct = await ProductModel.createPayload(req.body);
console.log(savedProduct,'saved_product')
let elaticDoc = await this.createElasticDocData(savedProduct);
console.log(elaticDoc.id,'elasticResult')
elaticDoc.id = result._id;
elaticDoc = new Elastic(elaticDoc);
console.log(elaticDoc,'<----------elaticdoc-------------->')
elasticResult = await elasticService.updateDocument(JSON.stringify(elaticDoc), req.body.Category)
console.log(elasticResult,'elasticResult')
}
else {
console.log('Here.... ADD')
const savedProduct = await ProductModel.createPayload(result);
let elaticDoc = await this.createElasticDocData(savedProduct);
elaticDoc.id = result._id;
elaticDoc = new Elastic(elaticDoc);
elasticResult = await elasticService.createDocument(JSON.stringify(elaticDoc), req.body.Category)
}
const response = new Response(1, "Product is saved successfully", "", "", { product: result, elasticResult: elasticResult });
return res.status(200).send(response);
}
const response = new Response(0, "Error in saving Product", 0, "Product not saved", {});
return res.status(200).send(response);
} catch (error) {
const response = new Response(0, "Unexpected Error", 0, error, {});
return res.status(400).send(response);
}
}
'''
This is the elasticappsearch file where above mentioned is coming from and for some reason it's not working after axios.patch part.
'''
const private_key = process.env.elastic_private_key
const search_key = process.env.elastic_search_key
const axios = require("axios")
class ElasticAppSearch {
async updateDocument(body, engine) {
console.log('Its coming in updateDOCS here')
const response = await axios.patch(`${process.env.elastic_url}/${engine}/documents`, body, {
headers: {
Authorization: `Bearer ${private_key}`,
},
});
console.log(response,'<--===-=-=-=-=-=-=-=-=-=-=-=-response')
return response.data
}
'''

Node.js: How to better write a MySQL batch operation code without too many callbacks?

I am not coming from a javascript background, however involved in writing a Node.js backend. There are situations where I have to do multiple database entry in a row and rollback if they failed. Below is such an example. (Node.js v14.17.5)
const mysql = require('mysql2');
const errorCodes = require('source/error-codes');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
const con = mysql.createConnection({
host: prop.get('server.host'),
user: prop.get("server.username"),
password: prop.get("server.password"),
port: prop.get("server.port"),
database: prop.get("server.dbname")
});
exports.createExtraGig = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
if (event.body == null && event.body == undefined) {
var response = errorCodes.missing_parameters;
callback(null, response)
} else {
let body = JSON.parse(event.body)
console.log("body", body);
// Check for validations
if (body.idjob_room == null ||
body.idgig_fund_status == null ||
body.title == null ||
body.cost == null ||
body.idjob == null ||
body.end_date == null
) {
console.log("fire 1");
var response = errorCodes.not_null_parameters;
callback(null, response)
} else {
if (
isNaN(body.idjob_room) ||
isNaN(body.idgig_fund_status) ||
isNaN(body.cost) ||
isNaN(body.idjob) ||
isNaN(body.end_date)) {
var response = errorCodes.missing_fields;
callback(null, response)
}
}
// Validations passed. Proceed
let idjob_room = Number(body.idjob_room);
let idgig_fund_status = Number(body.idgig_fund_status);
let title = body.title;
let cost = Number(body.cost);
let end_date = new Date(body.end_date);
let idjob = Number(body.idjob);
console.log("title: " + title);
con.beginTransaction(function(err){
if (err) {
var response = errorCodes.save_failed;
callback(null, response);
}
const sql = "INSERT INTO gig_service (idjob_room, idgig_fund_status, title, cost, end_date, is_deleted, is_main_offer) VALUES(?,?,?,?,?,?,?)";
con.query(sql, [idjob_room, idgig_fund_status, title, cost, end_date, false, false], function(err, gigResult) {
if (err) {
con.rollback(function() {
var response = errorCodes.save_failed;
callback(null, response);
});
}
const jobUpdateSql = "UPDATE job SET end_date=? WHERE idjob=?";
con.execute(jobUpdateSql, [end_date, idjob], function(err, jobResult) {
con.commit(function(err) {
if (err) {
return con.rollback(function() {
var response = errorCodes.save_failed;
callback(null, response);
});
}
console.log('success!');
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify({
"idgig_service": gigResult.insertId
}),
"isBase64Encoded": false
};
callback(null, response)
});
});
});
}
)}
};
However this is a maintenance hell, because the more transactions I have, more if-else conditions and more callbacks i have to make.
Looking at posts such as this tells me there are better ways, but i am really not sure.
How can I better write my Node.js code without having too many rollback callbacks? Like one rollback callback is "any" fails?
(Note: exports.createExtraGig = (event, context, callback) => line is important because this is an aws lambda function)
UPDATE
Below is the updated code
const mysql = require('mysql2');
const errorCodes = require('source/error-codes');
const PropertiesReader = require('properties-reader');
const prop = PropertiesReader('properties.properties');
const con = mysql.createConnection({
host: prop.get('server.host'),
user: prop.get("server.username"),
password: prop.get("server.password"),
port: prop.get("server.port"),
database: prop.get("server.dbname")
});
exports.createExtraGig = async (event, context)=>{
context.callbackWaitsForEmptyEventLoop = false;
if (event.body == null && event.body == undefined) {
var response = errorCodes.missing_parameters;
return response;
} else {
let body = JSON.parse(event.body)
console.log("body", body);
// Check for validations
if (body.idjob_room == null ||
body.idgig_fund_status == null ||
body.title == null ||
body.cost == null ||
body.idjob == null ||
body.end_date == null
) {
console.log("fire 1");
var response = errorCodes.not_null_parameters;
return response;
} else {
if (
isNaN(body.idjob_room) ||
isNaN(body.idgig_fund_status) ||
isNaN(body.cost) ||
isNaN(body.idjob) ||
isNaN(body.end_date)) {
var response = errorCodes.missing_fields;
return response;
}
}
// Validations passed. Proceed
let idjob_room = Number(body.idjob_room);
let idgig_fund_status = Number(body.idgig_fund_status);
let title = body.title;
let cost = Number(body.cost);
let end_date = new Date(body.end_date);
let idjob = Number(body.idjob);
console.log("title: " + title);
try {
await con.promise().beginTransaction();
const sql = "INSERT INTO gig_service (idjob_room, idgig_fund_status, title, cost, end_date, is_deleted, is_main_offer) VALUES(?,?,?,?,?,?,?)";
const gigResult = await con.promise().query(sql,[idjob_room, idgig_fund_status, title, cost, end_date, false, false]);
console.log(gigResult);
const jobUpdateSql = "UPDATE job SET end_date=? WHERE idjob=?";
await con.promise().query(jobUpdateSql,[end_date, idjob]);
await con.promise().commit();
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": JSON.stringify({
"idgig_service": gigResult.insertId
}),
"isBase64Encoded": false
};
return response;
} catch (error) {
console.log(error);
await con.promise().rollback();
return errorCodes.save_failed;
}
}
};
You can use promise with mysql.
const mysql = require('mysql2/promise');
// get the promise implementation, we will use bluebird
const bluebird = require('bluebird');
// create the connection, specify bluebird as Promise
const connection = await mysql.createConnection({host:'localhost', user: 'root', database: 'test', Promise: bluebird});
Then... (Ref: Async/Await )
try {
const resultsFromQuery1 = await con.query(sql1)
const resultsFromQuery2 = await con.query(sql2)
} catch (err) {
con.rollback(function() {
var response = errorCodes.save_failed;
callback(null, response);
});
}
You can also make your codes cleaner by using helpers like .some or .map
if (body.idjob_room == null ||
body.idgig_fund_status == null ||
body.title == null ||
body.cost == null ||
body.idjob == null ||
body.end_date == null)
//and the following chunk
isNaN(body.idjob_room) ||
isNaN(body.idgig_fund_status) ||
isNaN(body.cost) ||
isNaN(body.idjob) ||
isNaN(body.end_date))
can be written like
let { idgig_fund_status, title, cost, idjob, end_date } = body;
if ( [idgig_fund_status, title, cost, idjob, end_date].some(x => x === null )) {
var response = errorCodes.not_null_parameters;
callback(null, response)
} //can write similar for isNan checks
The following can also be written
let idjob_room = Number(body.idjob_room);
let idgig_fund_status = Number(body.idgig_fund_status);
let title = body.title;
let cost = Number(body.cost);
let end_date = new Date(body.end_date);
let idjob = Number(body.idjob);
//becomes...
[idjob_room, idgig_fund_status, cost, idjob] = [idgig_fund_status, cost, end_date, idjob].map(x => x+);
end_date = new Date(end)date;
//title is already deconstructed above.

How to call a javascript function inside another function in node js

I have a file index.js as below. Where I am trying to call a async function getConn in other function createThumbnails. But I am getting the error as "failed to connect to DEDC: 1433 - self signed certificate" in the catch block.
const sharp = require('sharp');
const sql = require('mssql')
// CONNECTION CONFIGURATION OF BASE DB
async function getConn() {
try {
const config = {
user: 'sa_user',
password: '*******',
server: 'DEDC',
database: 'DEMO_BASE'
}
const pool = await new sql.ConnectionPool(config)
const req=await pool.connect()
const conn = await req.request()
return conn;
} catch (err) {
return err;
}
};
const createThumbnails = async() => {
try{
var conn = await getConn();
const query = `exec DBBASE.get_client_info`
var clientusers = await conn.query(query);
} catch (err) {
return err;
}
}
createThumbnails()
How do I exactly call the function getConn inside createThumbnails. Please help. Thanks in advance
It's because you are using variable with the same name as the function.
Try different name:
var conn = await getConn();
const query = `exec DBBASE.get_client_info`
var clientusers = await conn.query(query);
You encounter what called hoisting. Kyle Simpson has a great explaination on this topic
var getConn = await getConn();
which means getConn will be initialized first, before assignment, which equivalents to
var getConn // initialized
getConn = await getConn() // assignment
Then turned out that you got the error
Solution here is to store it in a different variable name, like
var conn = await getConn();
async function getConn() {
return {
query: async () => {
console.log("query called");
},
};
}
const createThumbnails = async () => {
try {
var conn = await getConn();
const query = `exec DBBASE.get_client_info`;
var clientusers = await conn.query(query);
} catch (err) {
console.log(err);
}
};
createThumbnails();
We need to use trustServerCertificate: true in DB configuration i.e in const config

How to call a function directly through cmd to fetch and update records into database through Node js

I have a file CreateNewUserID.js, which has the code as below.
const Connection = require('./database/Connection')
const createNewUserID = async(connData, userId) => {
try{
var getConn = await Connection.get().getConn();
const query = `exec BaseDB.get_client_info`
var clientusers = await getConn.query(query);
var getConn1 = await Connection.get().getConnection(connData)
var res = await getConn1.execute('BaseDB.get_all_existing_users');
res.recordsets[1].map(async (val) => {
try{
var newid = val.id+'NEWID';
var getConn2 = await Connection.get().getConnection(connData)
getConn2.input('userid', userid)
getConn2.input('updatedid', newid)
var res2 = await getConn2.execute(`BaseDB.update_users_with_newid`)
} catch (err) {
console.log(err)
return { err, message: 'First DB Connection' }
}
})
} catch (err) {
console.log(err)
return { err, message: 'Second DB Connection' }
}
}
const connData = {
"clientuserid": "12345"
}
createNewUserID(connData)
Also I have a Connection.js where I have made DB connection configurations of Base Database and client DB.The client DB Database will be dynamic. So, for now I am passing the DB name through constant connData. I have defined connData in the same file above in CreateNewUserID.js.
My Connection.js is below:
const sql = require('mssql')
class Connection {
// CONNECTION CONFIGURATION OF CLIENT DB
getConnection = async (conData) => {
const connData = JSON.parse(conData)
try {
// sql.close();
const config = {
user: process.env.SQL_USER,
password: process.env.SQL_PASSWORD,
server: process.env.SQL_SERVER,
database: connData.clientuserid
}
const pool = await new sql.ConnectionPool(config)
const req=await pool.connect()
const conn = await req.request()
// const req = await sql.connect(config)
// const conn = await req.request()
return conn;
} catch (err) {
return err;
}
};
// CONNECTION CONFIGURATION OF BASE DB
getConn = async () => {
try {
// sql.close();
const config = {
user: process.env.SQL_USER,
password: process.env.SQL_PASSWORD,
server: process.env.SQL_SERVER,
database: process.env.SQL_DATABASE
}
const pool = await new sql.ConnectionPool(config)
const req=await pool.connect()
const conn = await req.request()
// const req = await sql.connect(config)
// const conn = await req.request()
return conn;
} catch (err) {
return err;
}
};
}
Connection.__instance = null;
Connection.get = () => {
if (!Connection.__instance) {
Connection.__instance = new Connection();
}
return Connection.__instance;
};
module.exports = Connection;
When I try to run the file through CMD with command node CreateNewUserID.js I am getting the error as unexpected token 0 in json at position 1 at first catch with message "First DB connection".
Why am I getting the error and how to resolve it. Please help. Thanks in advance

Categories

Resources