TypeScript correctly type a queryresult MySQL - mysql

I am using the mysql2/promise npm package for connecting and doing queries to a MySQL database. I got confused trying to set the correct typing for my query result, because I don't know in advance what type the result will be.
I have created a database class that has an async query method.
// Database.ts
import mysql, { Pool } from "mysql2/promise"; // import mysql2/promise
export class Database implements IDatabase {
logger: ILogger;
pool: Pool;
constructor(logger: ILogger) {
this.logger = logger;
// pool connection is set up here
}
async query(sql: string, options?: unknown): Promise<unknown> { // type?
const [rows] = await this.pool.query(sql, options);
return rows;
}
}
In my server code, I would like to be able do something like this:
// server.ts
import { Database } from "./core/Database";
const db = new Database(logger);
app.get("/", async (req, res) => {
const sql = `
select *
from users;
`;
const users: IUser[] = await db.query(sql); // get people
// do some logic x
// send response
res.json({
result: x
});
});
Using unknown doesn't work because I can't assign it to my type, using any does, but feels wrong. Is there a clean way to do this?

Type the function as:
async query<T = unknown>(sql: string, options?: unknown): Promise<T[]> {
Then use the function this way:
const users = await db.query<IUser>(sql);

With help of #Evert and this answer, I found a solution
I created following types:
export type DbDefaults = RowDataPacket[] | RowDataPacket[][] | OkPacket[] | OkPacket;
export type DbQueryResult<T> = T & DbDefaults;
Rewrote my method like this:
async query<T>(sql: string, options?: unknown): Promise<DbQueryResult<T[]>> {
const [result] = await this.pool.query<DbQueryResult<T[]>>(sql, options);
return result;
}
I can use it like this now:
const sql = `
select *
from users;
`;
const people = await db.query<IUser>(sql);
Just casting as T is also possible.
public async query<T>(sql: QueryString, parameters?: unknown[]): Promise<T[]> {
const [rows] = await this.pool.query(sql, parameters);
return rows as T[];
}

Related

How to compare password when using bcrypt nest js log in api in mysql

How I can compare password when signin in using bcrypt,I am facing problem at the time of signin for comparing password.From that select query i can get the matched mailid but how to get hash password?????????????????
note:I am not using typeorm...
Here is my service.ts code,
import { ConflictException, Injectable } from '#nestjs/common';
import { SignInDto,SignUpDto } from '../dto';
import { execute } from '../mysql';
import * as bcrypt from 'bcrypt';
import { FORMERR } from 'dns';
#Injectable()
export class AuthService {
// ------SignUp-------
public async CREATE(Dto: SignUpDto): Promise<any> {
const [account]:any = await execute(
`
SELECT
*
FROM
account
WHERE
email = ? AND
is_active = ? AND
is_deleted = ?
`,
[Dto.email.toLowerCase(), 1, 0],
);
if (account) {
throw new ConflictException('Account already exists on this email id.');
}
Dto.email = Dto.email.toLowerCase();
Dto.password = await bcrypt.hash(Dto.password, 12);
Dto.confirmPassword = await bcrypt.hash(Dto.confirmPassword, 12);
const data = { ...Dto};
return await execute(`INSERT INTO account SET ?`, [data]);
}
// -------SignIn---------
public async GET(Dto: SignInDto): Promise<any> {
const [isExist]:any = await execute(
`
SELECT
*
FROM
account
WHERE
email = ? AND
is_active = ? AND
is_deleted = ?
`,
[Dto.email.toLowerCase(), 1, 0],
);
*if (!isExist) {
const compare=await bcrypt.compare()
throw new ConflictException('Account does not exists.');
}*
return {
id: isExist.id,
};
}
}
conroller.ts
import { Controller, Post, Body, HttpCode, HttpStatus, Res, Get, ParseIntPipe, Param } from '#nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '#nestjs/swagger';
import { SignUpDto, SignInDto } from '../dto';
import { Response } from 'express';
import { AuthService } from './auth.service';
#Controller('auth')
export class AuthController {
constructor(private readonly _authService: AuthService) { }
#Post('/sign-up')
#HttpCode(HttpStatus.OK)
#ApiResponse({ status: HttpStatus.OK, description: 'Success' })
#ApiOperation({ summary: 'SignUp' })
public async SIGNUP(#Res() res: Response, #Body() Dto: SignUpDto): Promise<any> {
const result: any = await this._authService.CREATE(Dto);
if (result) {
return res.status(HttpStatus.OK).json({ status: HttpStatus.OK, message: `Registration completed successfully.` });
}
return res.status(HttpStatus.BAD_REQUEST).json({ status: HttpStatus.BAD_REQUEST, message: `Something went wrong. Please try again later.` });
}
#Post('/sign-in')
#HttpCode(HttpStatus.OK)
#ApiResponse({ status: HttpStatus.OK, description: 'Success.' })
#ApiOperation({ summary: 'SignIn' })
public async SIGNIN(#Res() res: Response, #Body() Dto: SignInDto): Promise<any> {
const result: any = await this._authService.GET(Dto);
if (result) {
res.status(HttpStatus.OK).json({ status: HttpStatus.OK, data: result, message: `Successfull` });
}
}
}
I am facing problem at the time of signin for comparing password.From that select query i can get the matched mailid but how to get hash password?????????????????
Thanks.....
First, there's no need to save the hashed confirmation password. The confirmation password should just be checked that it matches the password, to make sure the user sent in the password they expected to.
Second, assuming you have a password column, you should be able to get the password via isExist.password. Then you can check if the passwords are the same using bcrypt via bcrypt.compare(Dto.password, isExist.password). Bcrypt will take care of computing the same salt based on the hashed password (it's part of the hash actually). The compare method will return a boolean if the passed password hashes to the same hashed value and you can tell then if it was correct or not.

Use data accross all components

Created a component where I call all my api's. How do I use that data across all my other components
export let resultData = axios
.get(`https://swapi.dev/api/people/1`) //used a dummy api to test
.then(({ data }) => data);
export default class CacheService {
static myInstance = null;
result = resultData;
static getInstance() {
if (CacheService.myInstance == null) {
CacheService.myInstance = new CacheService();
}
return this.myInstance;
}
findAll() {
console.log(this.result);
return this.result;
}
}
You have created a promise and assigned to resultData variable but its not actually resolved.
Either you can use await or use then to get the data.
let testData = await newData.findAll();
or
newData.findAll().then((data)=>{
testData = data;
});
You need to await for the axios to resolve.
async findAll() {
const actualResult = await this.result;
console.log(actualResult);
return actualResult;
}

TypeError: Converting circular structure to JSON for mongodb/mongoose

var express = require("express")
let PersonModel = require('./PersonModel')
let mongodbConnected=require('./MongodbConnect')
var app =express()
var bodyparser=require("body-parser")
const { format } = require("path")
const { count } = require("console")
const { countDocuments } = require("./PersonModel")
const { exec } = require("child_process")
const { get } = require("http")
const { ALL } = require("dns")
app.use(bodyparser.urlencoded({extended:false}))
app.get('/',function(req,res){
res.sendFile('Person.html', { root: __dirname });
})
app.get('/about',function (req,res){
res.send("This is a simple express application using mongodb express html and mongoose")
PersonModel.countDocuments().exec()
.then(count=>{
console.log("Total documents Count before addition :", count)
}) .catch(err => {
console.error(err)
})
})
app.post('/add', function(req,res){
Pname=req.body.empname
console.log('Pname',Pname)
PAge=req.body.Age
PGender=req.body.gender
PSalary=req.body.salary
const doc1 = new PersonModel(
{
name:Pname,age:33,Gender:PGender,Salary
:PSalary}
)
doc1.save(function(err,doc){
if (err) return console.error(err)
else
console.log("doc is added ",doc)
//res.send("Record is added"+doc)
res.send({
'status':true,
'Status_Code':200,
'requested at': req.localtime,
'requrl':req.url,
'request Method':req.method,
'RecordAdded':doc});
}
)
})
app.post('/findperson', function(req,res){
PAge=req.body.Age
console.log("Page",PAge)
PersonModel.find({age:{$gte:PAge}})
// find all users
.sort({Salary: 1}) // sort ascending by firstName
.select('name Salary age')// Name and salary only
.limit(10) // limit to 10 items
.exec() // execute the query
.then(docs => {
console.log("Retrieving records ",docs)
res.send(docs)
})
.catch(err => {
console.error(err)})
})
app.post('/delete', function(req,res){
Pgender=req.body.gender
PersonModel.findOneAndDelete({Gender:Pgender }
).exec()
.then(docs=>{
console.log("Deleted")
console.log(docs); // Success
}).catch(function(error){
console.log(error); // Failure
});
})
app.post('/update', function(req,res){
Pname=req.body.empname
Pnewname=req.body.newname
PnewAge=req.body.newage
PersonModel.findOneAndUpdate({ name: Pname },{"$set":{name:Pnewname,age:PnewAge}}).exec()
.then(docs=>{
console.log("Update for what i get is ",Pname
,Pnewname,PnewAge)
console.log(docs); // Success
}).catch(function(error){
console.log(error); // Failure
});
})
var docnum=PersonModel.countDocuments(ALL)
app.post('/count', function(req, res){
res.send('Total number of documents: ', docnum)
})
app.listen(5000,function(){
console.log("Server is running on the port 5000")
})
Hello.
First time posting on stackoverflow, dont know what kind of information to post, please let me know.
Im trying to make a page (/count) to simply display the number of documents. I've tried different code but nothing is working. This error keeps coming up "TypeError: Converting circular structure to JSON".
This is school work so the code is given to me by a teacher and I have to add a POST method to add a page that displays total number of documents.
Any ideas?
Thanks.
Circular structure is not about mongo but how JS read the JSON object.
For example, if you have this object:
var object = {
propA: "propA",
propB: object
}
When JS try to deserialize JSON object, will handle that: One object contains the object that contain again the object and again and again... that is a circular dependence.
Not only with one object itself, aslo with more objects:
var objectA = {
propA: objectB
}
var objectB = {
propA: objectA
}
Is the same case.
Using node.js you can use util.inspecet() which automatically show [Circular] when a circular dependence is found.
You can use like this:
var util = require('util')
console.log(util.inspect(objectA))

Firebase Updating User Data With Custom Fields After Creating User

I want to update the newly created User's data. The returned JSON is:
{
"user":{
"uid":"test123",
"displayName":null,
"photoURL":null,
"email":"test12#test.com",
"emailVerified":false,
"phoneNumber":null,
"isAnonymous":false,
"tenantId":null,
"providerData":[
{
"uid":"test12#test.com",
"displayName":null,
"photoURL":null,
"email":"test12#test.com",
"phoneNumber":null,
"providerId":"password"
}
],
"apiKey":"test123",
"appName":"[DEFAULT]",
"authDomain":"test123.firebaseapp.com",
"stsTokenManager":{
"apiKey":"test123",
"refreshToken":"test123",
"accessToken":"test123",
"expirationTime":1571238989357
},
"redirectEventId":null,
"lastLoginAt":"1571235389108",
"createdAt":"1571235389108"
},
"credential":null,
"additionalUserInfo":{
"providerId":"password",
"isNewUser":true
},
"operationType":"signIn"
}
This is my callout and update:
createUser = async (userData) => {
return await firebase.auth().createUserWithEmailAndPassword(userData.get('userName'), userData.get('password'))
.then((authData) => {
firebase.database().ref('users/' + authData.user.uid + '/').set({
fullName: userData.get('fullName'),
pictures: userData.get('pictures'),
phoneNumber: userData.get('phoneNumber')
});
})
};
Is it possible to add to the User table custom fields?
A few things are happening. It appears that userData can not be seen in the .then statement. So to solve this I attempted to pass in the userData JSON as a param. This did not work. I then broke out each value out of userData, saved it into a const and passed that value. This did not work.
I can see that userData has values in it before the .then statement. I am able to successfully create a new user with the right userName and password. This means to me either:
A - I am not passing the userData JSON correctly or
B - I am not allowed to pass data to firebase like I am doing
My end goal is to sign up a user and then take all of the data they input from a registration form (aka userData) and update the user table with it.
Articles I am using are:
https://firebase.google.com/docs/auth/web/manage-users
https://medium.com/mindorks/firebase-realtime-database-with-react-native-5f357c6ee13b
Main class that calls the createUser function:
const signUp = (dispatch) => {
return async (userData)=>{
try{
const response = await config.createUser(userData);
console.log('sign up resonse1: ' + response); //coming back as undefined
//todo:: figure out how to parse out the apikey out of response
await AsyncStorage.setItem('token', '123mockToken');
dispatch({type: 'sign_up', payload: '123mockToken'});
navigate('mainFlow');
} catch(e){
dispatch({type: 'add_error', payload: '' + e}); //we call dispatch anytime we want to update our state
}
}
};
I understand that the parameter userData holds all the data you want to use for creating the user ("all of the data they input from a registration form").
The following should work:
createUser = async userData => {
try {
const userCredential = await firebase
.auth()
.createUserWithEmailAndPassword(
userData.get('userName'),
userData.get('password')
);
const userId = userCredential.user.uid;
await firebase
.database()
.ref('users/' + userId + '/')
.set({
fullName: userData.get('fullName'),
pictures: userData.get('pictures'),
phoneNumber: userData.get('phoneNumber')
});
return userId; //As per your comment below
} catch (error) {
return error;
}
};
The createUserWithEmailAndPassword() method returns a UserCredential which contains a User.

Access the common method from other component

Here I am using some method for frequently used methods in common method ts file. If I am going to access these method I got null values Please help me out.
CommonMethod.ts:
GetCategoryList(){
let Mylist = [];
this.auth.Get("Master/Category").then((user) => {
Mylist= user.json();
});
return Mylist;
}
My Another component:
I am trying to access common method ts file here. by below way.
import {CommonMethod} from './CommonMethod';
...
...
construtor(private com:CommonMethod){}
ngOninit(){
console.log(this.com.GetCategoryList());
}
this.auth.Get is going to be async in nature due to which the return MyList line will get called even before the callback to the then method is called and the data is arrived and set in MyList.
You can use the async await syntax to fix it:
async GetCategoryList() {
let Mylist = [];
const user = await this.auth.Get("Master/Category");
Mylist = user.json();
return Mylist;
}
You can then use it like this in your Component:
import {CommonMethod} from './CommonMethod';
...
...
construtor(private com: CommonMethod) {}
async ngOninit() {
const myList = await this.com.GetCategoryList();
console.log(myList);
}
PS: Make sure that CommonMethod is a service and is added to the providers array of your #NgModule
Should update your common method:
GetCategoryList(): Promise<any>{
let Mylist = [];
return this.auth.Get("Master/Category").then((user) => {
Mylist= user.json();
Promise.resolve(Mylist);
});
}
And
ngOninit(){
this.com.GetCategoryList().then(results=>{
console.log(results);
});
}