Node unhandel promises and imports oop - mysql

My code have an obj name SQLFeeter that need to do the sql interaction which get the data post it and pass it along I have some problem which is one imports. The babel doesn't work second while I try to get the data and pass it
const express = require('express');
const router = express.Router();
const mysql = require('mysql')
/*
--------------------------------------
This will handel all get requests
--------------------------------------
*/
/*
//sqlInteractuin test
const SqlDataGetter = require('../../sqlInteraction/GetData');
//import SqlDataGetter from "./sqlInteraction/GetData";
let SqlGetter = new SqlDataGetter
*/
class SqlDataGetter {
constructor()
{
this.con = mysql.createConnection({
host: "localhost",
user: "XXX",
password: "XXX",
database: "APP"
});
}
GetClients()
{
let con = mysql.createConnection({
host: "localhost",
user: "XXX",
password: "AAA",
database: "APP"
});
let resultFromSql = null;
con.connect(function(err) {
if (err) throw err;
let sql_query = "SELECT * FROM contacts"
con.query(sql_query , function (err, result, fields) {
if (err) throw err;
//console.log(fields);
console.log(result);
resultFromSql = result;
});
return resultFromSql;
});
}
Tester()
{
//return this.con
//console.log(this.con)
return 'hello world'
}
}
router.get('/' , async (req , res) =>
{
//Need to make an obj that take the data and do all the querys
res.status(200).send("DataBack");
});
router.get('/Clients' , async (req , res) =>
{
let sql_getter = new SqlDataGetter();
const Clients = sql_getter.GetClients();
console.log(Clients);
SqlDataGetter.GetClients()
res.status(200);
res.send({ respond : Clients});
});
While I am trying to run this at first it works on stand alone but when I create the ajax request it saying GetClients is not a function. And when I try to make the connection to be a property of this object as this.con when I activate this.con.query undifend property query of undifend.

If you use promise-mysql instead of mysql then you'll get promises from the method calls, which will make it easier to work with:
const mysql = require('promise-mysql');
Then your class would look like this:
class SqlDataGetter {
constructor() {
this.conPromise = mysql.createConnection({
host: "localhost",
user: "XXX",
password: "XXX",
database: "APP"
});
}
async GetClients() {
const con = await this.conPromise;
const result = await con.query("SELECT * FROM contacts");
console.log(result);
return result;
}
}
Finally, you'd use that class as follows:
router.get('/Clients' , async (req , res) => {
let sql_getter = new SqlDataGetter();
const clients = await sql_getter.GetClients();
console.log(clients);
res.status(200);
res.send({ respond : clients});
});

Related

Connecting Cypress V10++ into sql database [duplicate]

I get an error when running the integration tests:
0 passing (17s)
1 failure
1) Registration page
register new users allowed and update status in the database:
TypeError: Net.connect is not a function
at new Connection (webpack:///./node_modules/mysql2/lib/connection.js:50:0)
at ./node_modules/mysql2/index.js.exports.createConnection (webpack:///./node_modules/mysql2/index.js:10:0)
at Context.eval (webpack:///./cypress/integration/registration.spec.js:23:34)
Here is my environment:
MySQL Workbench
MySQL Server 8.0.29
I raised local backendless, I have access to the database. Here is my code:
const mysql2 = require('mysql2');
describe('Registration page', () => {
beforeEach(() => {
// visit the registration page
cy.visit('http://localhost:3000/registration');
});
it('register new users allowed and update status in the database', () => {
// fill out the registration form
cy.get('input[name="fullName"]').type("Nazar Dmytryshyn")
cy.get('input[type="email"]').type('testuser#example.com');
cy.get('input[name="pwd"]').type('testpassword');
cy.get('input[name="confirmPassword"]').type('testpassword');
// submit the form
cy.get('button[class="btn btn-success"]').click();
// check that the user is redirected to the login page
cy.url().should('include', '/login');
// create a connection to the test database
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
});
// open the connection
connection.connect();
// update the developer status in the database
connection.query(
'UPDATE `main_backendless`.`Developer` SET `developerStatusId` = "1" WHERE (`email` = "testuser#example.com")',
(error, results) => {
if (error) throw error;
expect(results.affectedRows).to.equal(1);
}
);
// close the connection
connection.end();
});
});
I checked this data 10 times, it is correct and I can connect to the database through MySQL WorkBench
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'main_backendless'
I will be grateful for any ideas that can be achieved!
I recommend using the cypress-mysql, which hides a lot of the implementation details for you.
If you try to roll your own task, you may end up with an undefined return value.
Install
npm install cypress-mysql
//or
yarn add cypress-mysql
Configure
The release notes are out of date, here is the configuration for Cypress 10+
// cypress.config.js
const { defineConfig } = require("cypress");
const mysql = require('cypress-mysql');
module.exports = defineConfig({
// ...
e2e: {
setupNodeEvents(on, config) {
mysql.configurePlugin(on);
},
"env": {
"db": {
"host": "localhost",
"user": "user",
"password": "password",
"database": "database"
}
}
})
// cypress/support/e2e.js
const mysql = require('cypress-mysql');
mysql.addCommands();
Test
const sql = 'UPDATE "main_backendless.Developer" SET "developerStatusId" = "1" WHERE ("email" = "testuser#example.com")'
cy.query(sql).then(res => {
expect(res.affectedRows).to.equal(1)
});
If you want to use a task to call the mySql library, you must return a Promise from the task.
This is because the mysql calls are asynchronous, and the only way Cypress knows to wait for them is to get a promise returned from your code.
cypress.config.js
const { defineConfig } = require("cypress")
const mysql2 = require('mysql2')
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
})
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
mySql: (sql) => {
return new Promise((resolve, reject) => {
connection.query(sql, (error, results) => {
if (error) {
reject(error)
} else {
resolve(results.affectedRows)
})
})
})
}
})
},
})
it('tests with mysql', () => {
cy.task('mySql', 'sql staement here')
.then(result => {
expect(result).to.equal(1);
})
})
With Promise-wrapper
Alternatively, mysql2 provides a promise-wrapper that can simplify your code:
const { defineConfig } = require("cypress")
const mysql = require('mysql2/promise') // different import here
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
})
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('task', {
mySql: async (sql) => { // async here
const result = await connection.execute(sql) // await here
return result;
}
})
},
})
The issue is that you're using a nodejs library with Cypress. Cypress tests execute inside a browser and cannot directly utilize nodejs libraries within a test.
To do what you want to need to create a cy.task() to be able to execute code in nodejs.
Assuming you're using js, create a file with a function to use the sql connector
// runSql.js
const mysql2 = require('mysql2');
function runSql(sql) {
const connection = mysql2.createConnection({
host: '127.0.0.1:3306',
user: 'root',
password: 'rootpassword',
database: 'local1'
});
connection.connect();
let rows;
connection.query(sql, (error, results) => {
if (error) throw error;
rows = results.affectedRows
});
connection.end();
return rows;
}
module.exports = runSql;
Then in the cypress.config.js file
const runSql = require('./runSql.js');
module.exports = defineConfig({
// ...
e2e: {
setupNodeEvents(on, config) {
on('task', {
runSql
});
},
});
Now to call the task in a test
describe('Registration page', () => {
it('test', () => {
const sql = 'UPDATE `main_backendless`.`Developer` SET `developerStatusId` = "1" WHERE (`email` = "testuser#example.com")';
cy.task('runSql', sql).then((rows) => {
expect(rows).to.equal(1);
});
});
});

In node.js, How to return mysql results from a function?

I tried to separate function to another file, as the function fetching data from mysql database.
This is db.js
const mysql = require('mysql');
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "sample"
});
con.connect()
module.exports = function(query) {
con.query(query, function (err, result) {
if (err){
console.log(err);
} else{
console.log(result)
return result
}
});
};
This is main.js
const express = require('express')
const db = require('./db')
const app = express()
app.get('/test', function(req, res){
var sql = "SELECT id FROM user"
console.log(db(sql))
res.send(db(sql))
});
In main.js on console.log(db(sql)) got undefined.
But in db.js on console.log(result) I got the values as:
[
RowDataPacket { id: 1 },
RowDataPacket { id: 2 },
RowDataPacket { id: 3 }
]
Why did I get undefined in the main.js? Is there any solution for this issue?
Since you are using callback function, you can't directly return the value from it.
you have 2 options to do what you want to do.
Promise
Async/Await (mysql2 module needed)
Try this,
Querying
function(query) {
return new Promise((resolve, reject) =>{
try{
con.query(query, function (err, result) {
if (err){
return reject(err)
}
return resolve(result)
});
}
catch(e){
reject(e)
}
})
};
Main
app.get('/test', async function(req, res){
var sql = "SELECT id FROM user"
try{
const userId = await db(sql)
return res.send({
success: true,
result: {
userId
}
})
}
catch(e){
console.error(e)
return res.status(500).send({
success: false,
message: 'internal server error'
})
}
})
One more thing, if you have a good reason to write query by yourself, you can use
knex for making it easier (https://www.npmjs.com/package/knex), which is a query builder, meaning doing nothing to do with database connection.
Sollution
Try async/await with mysql2
Dont go for mysql2/primse because it will cause unexpected errors when your database is in the cloud or deployed somewhere like clearDB addons provided by Heroku
Follow these steps...
create config file for your database connection seperately
import mysql from 'mysql2'
let db = mysql.createPool({
host: 'your host name',
user: "your username",
password: "your password",
database: "your database name",
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
export { db }
execute the query the same like this i am doing
import {db} from 'where you defined the above db config'
app.get('/test', async function(req, res){
const promise= db.promise()
var sql = "SELECT id FROM user"
const [rows,field] = awiat promise.execute(sql)
res.send(rows)
});

How to mock promisify call on mysql query nodeJS using sinon and Mocha?

This is my code using mysql -
import * as mysql from 'mysql';
import {promisify} from 'util';
const connectionParams:any = {
/* set as environment variables */
host: host,
user: user,
password: password,
port: parseInt(port)
};
var connection:any;
const getRecords = async (inputValue: string) => {
//validate inputValue
const userIds: string[] = [];
logger.info("Creating mysql connection");
try {
connection = mysql.createConnection(connectionParams);
const query = promisify(connection.query).bind(connection);
const queryResult = await query({ sql: sqlQuery, timeout: 1000, values: value1, inputValue] });
if (queryResult) {
queryResult.forEach((row) => {
userIds.push(row.userid);
});
}
} catch (error) {
logger.info(error);
// console.log(error);
throw new Error('Could not retrieve user IDs');
} finally {
connection.end();
}
return userIds;
};
And this is my test -
it('should return a list of records when right inputs are given', async() => {
sinon.stub(process, 'env').value({
'database': 'TESTDB'
});
let dummyArray = [{ userid: 'xyz' }];
let createConnection = {
connect: function(connectionParams: any) {
return Promise.resolve()
},
query : sinon.stub().withArgs({}).callsFake(function (...args): Promise<Object>{
const dummyArray = [{ userid: 'xyz' }];
return new Promise(function(resolve){resolve(dummyArray)});
}),
end: function() {}
};
let mySqlStub = {
createConnection: sinon.stub().returns(createConnection)
};
const dbops = proxyquire('../../lib/dbops', {'mysql': mySqlStub}).default;
expect(await dbops.getUserIds('Delete')).to.deep.equal(['xyz']);
});
How do I write the fake function for the query?
query : sinon.stub().withArgs({}).callsFake(function (...args):
Promise{
const dummyArray = [{ userid: 'xyz' }];
return new Promise(function(resolve){resolve(dummyArray)});
})
This does not work for me. How can I get this to work? I cannot get the stub function to resolve and return the intended value in the main function. The query just hangs and throws an error after the timeout. The error is happening in "matchingfakes" method within the stub.
proxyquire is used for stubbing the standalone function exports from a module or package. Since mysql is an object, you can stub its methods by sinon.stub(obj, 'method'). You don't need to use use proxyquire package.
Even if you use util.promisify to generate promise versions for the NodeJS error-First callback method(mysql.query(sql, callback), the callback signature is function (error, results, ...args): void). You need to use .callsFake() to create a mock implementation for this method, and trigger the promise version by calling its callback.
And, you should import the function after stubbing the environment variables. Because when you import the ./dbops module, the code in the module scope will be executed immediately, at this time, the environment variables are not stubbed.
E.g.
dbops.ts:
import mysql from 'mysql';
import { promisify } from 'util';
const connectionParams: any = {
host: process.env.HOST,
user: process.env.USER,
password: process.env.PASSWORD,
port: parseInt(process.env.PORT || '3306'),
};
var connection: any;
const getRecords = async (inputValue: string) => {
const sqlQuery = 'SELECT * FROM tests';
const value1 = '';
const userIds: string[] = [];
console.info('Creating mysql connection');
try {
connection = mysql.createConnection(connectionParams);
const query = promisify(connection.query).bind(connection);
const queryResult = await query({ sql: sqlQuery, timeout: 1000, values: value1, inputValue });
if (queryResult) {
queryResult.forEach((row) => {
userIds.push(row.userid);
});
}
} catch (error) {
console.info(error);
throw new Error('Could not retrieve user IDs');
} finally {
connection.end();
}
return userIds;
};
export { getRecords };
dbops.test.ts:
import sinon from 'sinon';
import mysql from 'mysql';
describe('69702002', () => {
it('should return a list of records when right inputs are given', async () => {
sinon.stub(process, 'env').value({
HOST: '127.0.0.1',
USER: 'testuser',
PASSWORD: 'testpwd',
PORT: '3306',
});
const { getRecords } = await import('./dbops');
const dummyArray = [{ userid: 'xyz' }];
let connectionStub = {
query: sinon.stub().callsFake((sql, callback) => {
callback(null, dummyArray);
}),
end: sinon.stub(),
};
sinon.stub(mysql, 'createConnection').returns(connectionStub);
const actual = await getRecords('test input');
sinon.assert.match(actual, ['xyz']);
sinon.assert.calledWithExactly(mysql.createConnection, {
host: '127.0.0.1',
user: 'testuser',
password: 'testpwd',
port: 3306,
});
sinon.assert.calledOnce(connectionStub.end);
});
});
test result:
69702002
Creating mysql connection
✓ should return a list of records when right inputs are given (945ms)
1 passing (952ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 90.48 | 50 | 100 | 90 |
dbops.ts | 90.48 | 50 | 100 | 90 | 27-28
----------|---------|----------|---------|---------|-------------------

web browser crashes when using mysql prepared query with nodejs

I want to return the result of query to DB, which I think would be a promise and then consume that promise in another file.Here is my model code (User.js) :
User.prototype.login = function () {
return new Promise((resolve, reject) => {
pool.execute('SELECT * FROM `users` WHERE `username` = ? AND `password` = ?', [this.data.username, this.data.password], (err, attemptedUser) => {
if (err) {
pool.release();
return reject(err);
} else {
pool.release();
return resolve(attemptedUser);
}
});
});
}
and the code in my controller file (userController.js):
const User = require('../models/User');
exports.login = (req, res) => {
let user = new User(req.body);
user.login()
.then((result) => {
res.send(result);
})
.catch((err) => {
res.send(err);
});
};
But when I click on the login button the page doesn't go to the specified URL and keeps working until crash.
Where is the problem?
UPDATE-1
This is my db.js :
const mysql = require('mysql2/promise');
const dotenv = require('dotenv');
dotenv.config();
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: 100
});
module.exports = pool;

How to make a function to query MySQL in NodeJS?

I made this:
const mysql = require('mysql2/promise')
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: '',
database: 'nodejs',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
async function query(query) {
const result = await pool.query(query)
return result[0]
}
console.log(query('SELECT * FROM `users`'))
and I got back
Promise { <pending> }
How do I get back my results from querying the database, just like PHP can do?
In PHP I never had to do such a thing like async/await and promises...
I also tried using mysql:
const mysql = require('mysql')
const db = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database : 'nodejs'
})
function query(query) {
db.query(query, (err, result) => {
if (err) throw err
return result
})
}
console.log(query('SELECT * FROM `users`'))
but I got an undefined result
try this:
var mysql = require('mysql');
var con = mysql.createConnection({
host: "localhost",
user: "yourusername",
password: "yourpassword",
database: "mydb"
});
// function definition
function runQuery (con, sqlQuery) {
return new Promise((resolve, reject) => {
console.log("START");
if(con){
con.connect(function (err) {
if (err) throw err;
});
if (sqlQuery) {
con.query(sqlQuery, function (error, result, fields) {
connection.end(); // end connection
if (error) {
throw error;
} else {
return resolve(result);
}
});
} else {
connection.end(); // end connection
// code: handle the case
}
} else {
// code: handle the case
}
});
}
var sqlQuery = 'SELECT * FROM tableName';
// function call and pass the connection and sql query you want to execute
var p = runQuery(con, sqlQuery);
p.then((data)=>{ // promise and callback function
console.log('data :', data); // result
console.log("END");
});
I am not very familiar with MySQL and the libraries that you are using.
However, the Promise { <pending> } response that you are getting is because you didn't await your query execution.
Since the function is marked as async and is also performing an async action, it returns a Promise that needs to be awaited to be resolved.
The code below should work:
const mysql = require('mysql2/promise')
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: '',
database: 'nodejs',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
async function query(query) {
const result = await pool.query(query)
return result[0]
}
(async () => {
const queryResult = await query('SELECT * FROM `users`');
console.log(queryResult);
} )();
To understand how async-await works, consider the code below:
console.log('I will get printed first');
const asyncFunction = async () => {
await setTimeout(()=> {}, 1000)
console.log('I will get printed third');
return 'hello'
}
(async () => {
const result = await asyncFunction();
console.log(`I will get printed last with result: ${result}`);
})();
console.log('I will get printed second');
The console.log statement I will get printed last with result will wait for the asyncFunction to complete execution before getting executed.
Try this:
var mysql = require('mysql');
var con = mysql.createConnection({
host: "localhost",
user: "yourusername",
password: "yourpassword",
database: "mydb"
});
con.connect(function(err) {
if (err) throw err;
con.query("SELECT * FROM customers", function (err, result, fields) {
if (err) throw err;
console.log(result);
});
});