Graphql Mysql - Get rows from a table in JSON Format - node.js

I'm working on Backend with TypeGraphQL and NodePostGres.
User will pass database id and table name. I need to send data in JSON Format.
I have tried below code but it doesn't return anything nor does it throw any error.
Service:
import { Service } from 'typedi'
import { Client } from 'pg'
import { databases } from './db'
import { Payload } from './models'
#Service()
export class PayloadService {
fetchPayload(id: number, tableName: string): Payload {
const databaseCredentials = databases.find((d) => d.id && +d.id === id)
if (!databaseCredentials) throw new Error('Invalid ID!')
const client = new Client({
host: databaseCredentials.host,
port: +(databaseCredentials.port || 5432),
user: databaseCredentials.username,
password: databaseCredentials.password,
database: databaseCredentials.database,
ssl: {
rejectUnauthorized: false,
},
})
console.log('before client')
client.query("select * from pg_tables where schemaname='public'", (err, res) => {
if (err) {
console.log(err.stack)
} else {
console.log(res.rows[0])
}
console.log(`callback`)
})
console.log('after client')
return {
id,
data: [],
}
}
}
Resolver:
import { Arg, Query, Resolver } from 'type-graphql'
import { Inject } from 'typedi'
import { Payload } from './models'
import { PayloadService } from './services'
#Resolver(Payload)
export class PayloadResolver {
#Inject()
private PayloadService: PayloadService
#Query((returns) => Payload)
payload(#Arg('databaseId') databaseId: number, #Arg('tableName') tableName: string) {
return this.PayloadService.fetchPayload(databaseId, tableName)
}
}

Related

GraphQL Subscriptions is null using Express-GraphQL and graphql-subscriptions

I am using TypeScript and have Server and Client application. Below is the server code.
Server Code
import express, { Express } from "express";
import { graphqlHTTP } from "express-graphql";
import { buildSchema } from "type-graphql";
import { TaskResolver } from "./resolvers/task.resolver";
import { pgDatasource } from "./configs/db.config";
import { SeatBandingResolver } from "./resolvers/seatBanding.resolver";
import { GuestChatResolver } from "./resolvers/guestChat.resolver";
import { RateResolver } from "./resolvers/rate.resolver";
import { YearResolver } from "./resolvers/year.resolver";
import { ImplementationRateResolver } from "./resolvers/implementationRate.resolver";
import { UserResolver } from "./resolvers/user.resolver";
import { ReportResolver } from "./resolvers/report.resolver";
// Subscriptions
const ws = require("ws");
const { useServer } = require("graphql-ws/lib/use/ws");
const { execute, subscribe } = require("graphql");
const main = async () => {
const app: Express = express();
try {
//connect to db
await pgDatasource.initialize();
} catch (err) {
throw err;
}
//build gql schema
let schema = await buildSchema({
resolvers: [
SeatBandingResolver,
GuestChatResolver,
RateResolver,
YearResolver,
ImplementationRateResolver,
UserResolver,
],
validate: false,
// pubSub: new PubSub()
});
let schemaDoc = await buildSchema({
resolvers: [ReportResolver],
validate: false,
});
//ql schema for report
const docServer = graphqlHTTP((req, res) => {
return {
schema: schemaDoc,
graphiql: true,
context: {
req: req,
header: req.headers,
},
};
});
//setting a graphql server instance
const graphqServer = graphqlHTTP((req, res, graphQLParams) => {
return {
schema,
context: {
req: req,
header: req.headers,
},
graphiql: true,
};
});
app.use(cors());
//graphql endpoint : change it to backend
app.use("/graphql", graphqServer);
//for report : change name to google api
app.use("/doc", docServer);
//test route
app.get("/", (req, res) => {
res.json({
message: "Hello world",
});
});
let server = app.listen(3001, () => {
console.log("server started");
const wsServer = new ws.WebSocketServer({
host: "localhost",
// server,
path: "/graphql",
port: 3001,
});
useServer(
{
schema,
execute,
subscribe,
onConnect: (ctx) => {
console.log("Connect");
},
onSubscribe: (ctx, msg) => {
console.log("Subscribe");
},
onNext: (ctx, msg, args, result) => {
console.debug("Next");
},
onError: (ctx, msg, errors) => {
console.error("Error");
},
onComplete: (ctx, msg) => {
console.log("Complete");
},
},
wsServer
);
});
};
//starting a server
main()
.then(async (_) => {
// await addColumn()
})
.catch((err) => {
console.log(err);
});
Subscription Code at Client Side
import { Year } from "../entities/year.entity";
import { NewYear } from "../inputs/addYear.input";
import {
Arg,
Ctx,
Field,
Int,
Mutation,
ObjectType,
Query,
Resolver,
Root,
Subscription,
UseMiddleware,
} from "type-graphql";
import { Request } from "express";
import { Response } from "../helpers/response.helper";
import { Pagination } from "../inputs/pagination.input";
import { isAuth } from "../helpers/auth.helper";
import { PubSub, PubSubEngine } from "graphql-subscriptions";
const pubSub = new PubSub();
#ObjectType()
class MessagePayload {
#Field()
message: string;
}
#Resolver(() => Year)
export class YearResolver {
#Mutation(() => String)
async sendMessage(#Arg("message") message: string): Promise<string> {
console.log("in send subscription");
pubSub.publish("MESSAGE_NOTIFICATION", { message });
return message;
}
//calling the subscription
#Subscription(() => MessagePayload || null, {
topics: "MESSAGE_NOTIFICATION",
})
async receiveMessage(
#Root() root: MessagePayload
): Promise<MessagePayload | null> {
console.log("in publisher");
console.log(root, "in recieve message");
pubSub.asyncIterator("MESSAGE_NOTIFICATION");
return { message: "hello from the subscription" };
}
}
The issue I am facing here is Subscription is not working properly and the data is always null.
Can anyone help me to identify what I am missing here?
Thanks.
I'm not sure for 100% because your code descriptions are kinda confusing, but it looks like you should return pubSub.asyncIterator('MESSAGE_NOTIFICATION') in method receiveMessage. This method is called to start streaming messages to client at selected channel (MESSAGE_NOTIFICATION), not sending them. To send messages use pubsub. Of course you should change typing too.
You can find a similiar implementation here.

Return of api rest with node

Im trying to generate rest-api for Odoo - ERP whith Nestjs and odoo-xmlrpc. I can connect to odoo but i cant respose the values than odoo response to my service.
This is the odoo service that response a value or an error:
import { Injectable, OnModuleInit } from '#nestjs/common';
#Injectable()
export class OdooService {
private Odoo = require('odoo-xmlrpc');
public odoo;
constructor () {
this.odoo = new this.Odoo({
url: 'https:/www.xxxxxxxxx.xxx',
db: 'xxxx',
username: 'username',
password: 'password'
});
}
execute(model: string, funtion: string , params: any[], callback) {
const odoo = new this.Odoo({
url: 'https:/www.xxxxxxxxx.xxx',
db: 'xxxx',
username: 'username',
password: 'password'
});
odoo.connect(async function (error: any): Promise<any> {
if (error) {
console.log(error);
return [{}];
}
odoo.execute_kw(model, funtion, params, function (error: any, values: []) {
if (error) {
console.log('error :>> ', error);
return [{}];
}
callback(values);
})
})
}
}
this is the service that use the odooServive
import { Injectable } from '#nestjs/common';
import { OdooService } from '../odoo/odoo.service';
import { CreateCountryDto } from './dto/create-country.dto';
import { UpdateCountryDto } from './dto/update-country.dto';
#Injectable()
export class CountriesService {
constructor(
private odooService: OdooService
) {}
async findAll() {
return await this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }], async function (response: []) {
// console.log(response);
return await response;
});
}
}
odoo documentation: https://www.odoo.com/documentation/14.0/webservices/odoo.html
library documentation: https://www.npmjs.com/package/odoo-xmlrpc
Elaborating #charlietfl's comment into an answer, you can use one of these codes, either using callback, or using async await
No Promise, no callback
findAll() {
return this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }]);
}
Using callback, no need for Promise
findAll() {
this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }], function (response: []) {
return response;
});
}
Using Promise
async findAll() {
const response = await this.odooService.execute('res.country', 'search_read', [[[]], { fields: ['name'] }]);
return response;
}

Unable to create Jest testing module on NestJs service. Geting Nest can't resolve dependencies of the UsersService (?, ConfigService)

it's my first time making questions on stackoverflow :).
So I'm developing a test / learning application to learn how to use NestJS and Vue.
I am was currently trying to implement several server-side unit tests (using Jest). When trying to create a testingmodule from my UsersService I get the error below on running "npm test users.service.spec"
Nest can't resolve dependencies of the UsersService (?,
ConfigService). Please make sure that the argument at index [0] is
available in the _RootTestModule context.
at Injector.lookupComponentInExports (../node_modules/#nestjs/core/injector/injector.js:183:19)
I am not sure if I am incorrectly instantiating the test model, or misconceived the injection of config.service, the code itself works, but may be implemented incorrectly.
Does anyone have any ideas how to solve this problem?
Git link: https://github.com/Lindul/FuelTracker_NestJs_MySql_Vue.git
users.service.spec.ts
import { Test } from '#nestjs/testing';
import { UsersService } from './users.service';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { ConfigService } from '../shared/config/config.service';
describe('User Service Tests', () => {
let loginTeste: UserLoginRegRequestDto = {
login: 'LoginJestTeste',
password: 'PassJestTeste',
}
const userMock: UserDto = {
id: 1,
login: 'hugombsantos',
password: 'wefewkfnwekfnwekjnf',
isActive: true,
needChangePass: false,
userType: 0,
};
const dataFindAllMock: UserDto[] = [{
id: 1,
login: 'hugombsantos',
password: 'wefewkfnwekfnwekjnf',
isActive: true,
needChangePass: false,
userType: 0,
}, {
id: 2,
login: 'user2',
password: 'sdgsdgdsgsdgsgsdg',
isActive: true,
needChangePass: false,
userType: 0,
}];
let service: UsersService;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
ConfigService,
UsersService,
],
}).compile();
service = module.get<UsersService>(UsersService);
});
it('UsersService está defenido', () => {
expect(service).toBeDefined();
});
});
user.service.ts
import { Injectable, Inject, HttpException, HttpStatus } from '#nestjs/common';
import { Users } from '../models/users.schema';
import { UserDto } from './dto/user.dto';
import { UserLoginRegRequestDto } from './dto/user-login-reg-request.dto';
import { UserLoginResponseDto } from './dto/user-login-response.dto';
import { sign } from 'jsonwebtoken';
import { ConfigService } from '../shared/config/config.service';
import { JwtPayload } from './auth/jwt-payload.model';
import { ErroMessageDto } from '../shared/config/dto/erro-message.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import bcrypt = require('bcrypt-nodejs');
const SALT_FACTOR = 8;
#Injectable()
export class UsersService {
constructor(
#Inject('UsersRepository') private usersRepository: typeof Users,
private readonly configService: ConfigService,
) { }
/* istanbul ignore next */
async findAll(): Promise<UserDto[]> {
const users = await this.usersRepository.findAll<Users>();
return users.map(user => {
return new UserDto(user);
});
}
/* istanbul ignore next */
async findUser(id: number): Promise<Users> {
const user = await this.usersRepository.findOne<Users>({
where: { id },
});
return user;
}
/* istanbul ignore next */
async findUserformLogin(login: string): Promise<UserDto> {
return await this.usersRepository.findOne<Users>({
where: { login },
});
}
/* istanbul ignore next */
async findUserforLogin(id: number, login: string): Promise<Users> {
return await this.usersRepository.findOne<Users>({
where: { id, login },
});
}
/* istanbul ignore next */
async creatUserOnDb(createUser: UserLoginRegRequestDto): Promise<Users> {
try {
const user = new Users();
user.login = createUser.login;
user.password = await this.hashPass(createUser.password);
return await user.save();
} catch (err) {
if (err.original.code === 'ER_DUP_ENTRY') {
throw new HttpException(
new ErroMessageDto(
HttpStatus.CONFLICT,
`Login '${err.errors[0].value}' already exists`),
HttpStatus.CONFLICT,
);
}
throw new HttpException(
new ErroMessageDto(
HttpStatus.INTERNAL_SERVER_ERROR,
err),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
/* istanbul ignore next */
async updateUserOnDb(user: Users): Promise<Users> {
try {
return await user.save();
} catch (err) {
if (err.original.code === 'ER_DUP_ENTRY') {
throw new HttpException(
new ErroMessageDto(
HttpStatus.CONFLICT,
`Login '${err.errors[0].value}' already exists`),
HttpStatus.CONFLICT,
);
}
throw new HttpException(
new ErroMessageDto(
HttpStatus.INTERNAL_SERVER_ERROR,
err),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
/* istanbul ignore next */
async delete(id: number): Promise<UserDto> {
const user = await this.findUser(+id);
await user.destroy();
return new UserDto(user);
}
async login(
userLoginRequestDto: UserLoginRegRequestDto,
): Promise<UserLoginResponseDto> {
const login = userLoginRequestDto.login;
const password = userLoginRequestDto.password;
const user = await this.findUserformLogin(login);
if (!user) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.UNAUTHORIZED,
'Invalid login or password.'),
HttpStatus.UNAUTHORIZED,
);
}
const isMatch = await this.comparePass(password, user.password);
if (!isMatch) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.UNAUTHORIZED,
'Invalid login or password.'),
HttpStatus.UNAUTHORIZED,
);
}
const token = await this.signToken(user);
return new UserLoginResponseDto(token);
}
async create(createUser: UserLoginRegRequestDto): Promise<UserLoginResponseDto> {
const userData = await this.creatUserOnDb(createUser);
// when registering then log user in automatically by returning a token
const token = await this.signToken(userData);
return new UserLoginResponseDto(token);
}
async updateUser(id: number | string, updateUserDto: UpdateUserDto): Promise<UserLoginResponseDto> {
const user = await this.findUser(+id);
if (!user) {
throw new HttpException(
new ErroMessageDto(
HttpStatus.NOT_FOUND,
'User not found.'),
HttpStatus.NOT_FOUND,
);
}
user.login = updateUserDto.login || user.login;
user.userType = updateUserDto.userType || user.userType;
user.needChangePass = false;
const isMatch = await this.comparePass(updateUserDto.password, user.password);
if (updateUserDto.password && !isMatch) {
user.password = await this.hashPass(updateUserDto.password);
} else {
user.password = user.password;
}
const userData = await this.updateUserOnDb(user);
const token = await this.signToken(userData);
return new UserLoginResponseDto(token);
}
async signToken(user: UserDto): Promise<string> {
const payload: JwtPayload = {
id: user.id,
login: user.login,
};
const token = sign(payload, this.configService.jwtConfig.jwtPrivateKey,
{
expiresIn: this.configService.jwtConfig.valideTime,
});
return token;
}
async hashPass(passToHash: string): Promise<string> {
const saltValue = await bcrypt.genSaltSync(SALT_FACTOR);
return await bcrypt.hashSync(passToHash, saltValue);
}
async comparePass(passToCheck: string, correntPass: string) {
return await bcrypt.compareSync(passToCheck, correntPass);
}
}
users.modules.ts
import { Module } from '#nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import {userProviders} from './users.providers';
import { DatabaseModule } from '../database/database.module';
import { JwtStrategy } from './auth/jwt-strategy';
import { ConfigService } from '../shared/config/config.service';
#Module({
imports: [DatabaseModule, ConfigService],
controllers: [UsersController],
providers: [UsersService,
...userProviders, JwtStrategy],
exports: [UsersService],
})
export class UsersModule {}
config.service.ts
import { Injectable } from '#nestjs/common';
import { JwtConfig } from './interfaces/jwt-config.interface';
import { config } from '../../../config/config.JwT';
import { config as dbConfigData } from '../../../config/config.db';
import { SequelizeOrmConfig } from './interfaces/sequelize-orm-config.interface';
#Injectable()
export class ConfigService {
get sequelizeOrmConfig(): SequelizeOrmConfig {
return dbConfigData.databaseOpt;
}
get jwtConfig(): JwtConfig {
return {
jwtPrivateKey: config.jwtPrivateKey,
valideTime: config.valideTime,
};
}
}
You need to provide some value for Nest to inject for your UserRepository. It looks like you are using the TypeORM #InjectRepository() decorator, so in your testing module you'll need to add something like this under your providers
{
provide: getRepositoryToken('UsersRepository'),
useValue: MyMockUserRepo,
}
So that Nest can know what value to inject for that string. MyMockUserRepo would be your mock repository functionality, so that you aren't making actual database calls to your backend

How to call function with Babel

I try call function with hapi-cron-job, but I get always error:
worker.js:54 execute: _cronsAntpool2['default'].account('btc'),
TypeError: Cannot read property 'account' of undefined
My worker.js has this code:
/**
* Imports
*/
import Hapi from 'hapi';
import schedule from 'hapi-cron-job';
import config from './config';
import Antpool from './crons/antpool';
/**
* Server setup
*/
const server = new Hapi.Server({
connections: {
router: {
stripTrailingSlash: true
}
}
});
server.connection({
host: config.app.workerhost,
port: config.app.workerport,
routes: {
cors: {
additionalHeaders: [
'Origin'
]
}
}
});
server.register({
register:require('hapi-cron-job'),
options:{
localTime: false, //GMT
jobs:[
{
name: "antpool - account - btc",
enabled: true,
immediate: true,
schedule: "every 24 hours",
execute: Antpool.account('btc'),
environments: ['development','production']
}
],
callback: callback
}
}, function(err){
if(err) { throw err; }
});
The function, which is called:
/**
* Imports
*/
import {signature} from '../core/antpool';
import log from '../core/logging';
import config from '../config';
import {sendLog as sendEmailLog, EmailTemplate} from '../core/email';
import {rethinkdb, Decorators as DBDecorators} from '../core/db';
import request from 'request';
const tables = {
AntpoolAccount: 'CronAntpoolAccount'
};
class Antpool {
#DBDecorators.table(tables.AntpoolAccount)
account(coin) {
var nonce = Date.now();
request.post({
url: config.antpool.baseUrl + '/api/account.htm',
json: true,
form: {
key: config.antpool.key,
nonce: nonce,
signature: signature(nonce),
coin: coin
}
}, function (err, httpResponse, body) {
if (err || httpResponse.statusCode != 201) {
log.error(err, '[CRON][Antpool][Account] Connection problem');
sendEmailLog(EmailTemplate.LOG, {
message: '[CRON][Antpool][Account] Connection problem'
});
return false;
}
var out = JSON.parse(body);
if (out.code != 0) {
log.error(err, '[CRON][Antpool][Account] Error response('+out.code+'): '+out.message);
sendEmailLog(EmailTemplate.LOG, {
message: '[CRON][Antpool][Account] Error response('+out.code+'): '+out.message
});
return false;
}
// Add to database
let obj = {
earn24: out.data.earn24Hours,
earnTot: out.data.earnTotal,
paidOut: out.data.paidOut,
balance: out.data.balance,
createdAt: new Date()
};
// Insert into database
let insert = this.table.insert(obj).run();
if(insert) {
return true;
} else {
return false;
}
});
}
}
/**
* Exports
*/
export {Antpool};
I am trying find the correct calling. But get always the error.
Seems problem with line execute: Antpool.account('btc'), in worker.js.
Any idea how to proper call function helps for me.
I am using Babel v. 5.8.38

Having issues with connection when using node-mssql connected with Azure sql database

I'm trying to insert the data from Bitfinex api into table rows of my database. I use node with typescript and mssql to execute the data service. Sometimes it works and I see the data is inserted, but sometimes the console log shows
"connection error: connection is not opened yet"
I don't even know why and where the root cause is.
Below is my code:
app-data-service.ts
import * as mssql from 'mssql';
import { AppConfig } from '../config';
import { LendbookService, UsersService, MockUsersService } from './data-services';
import { MOCK_USERS } from './mock-data';
import { Logger, LoggerFactory } from '../common';
export class AppDataServices {
private static readonly LOGGER: Logger = LoggerFactory.getLogger();
private db: any;
public usersService: UsersService;
public lendbookService: LendbookService;
constructor(private appConfig: AppConfig) {
this.initConnectionPool();
this.usersService = new MockUsersService(MOCK_USERS);
this.lendbookService = new LendbookService(this.db, AppDataServices.LOGGER);
}
private initConnectionPool() {
this.db = new mssql.ConnectionPool({
user: this.appConfig.mssqlUsername,
password: this.appConfig.mssqlPassword,
server: this.appConfig.mssqlServer,
database: this.appConfig.mssqlDatabase,
// If you are on Microsoft Azure, you need this:
options: { encrypt: true }
}, (err: any) => {
if (err) AppDataServices.LOGGER.error('MSSQL error', err);
});
}
}
lendbook-service.ts
import * as mssql from 'mssql';
import { Lendbook } from '../../models';
import { Logger, LoggerFactory } from '../../../common';
export class LendbookService {
private static readonly LOGGER: Logger = LoggerFactory.getLogger();
constructor(private db: any, private logger: any) {}
insert(row: object): any {
const sql = "INSERT INTO dbo.lendbook (rate, amount, period, timestamp, type, frr) VALUES (#rate, #amount, #period, #timestamp, #type, #frr)";
const ps = new mssql.PreparedStatement(this.db);
ps.input('rate', mssql.Decimal);
ps.input('amount', mssql.Decimal);
ps.input('period', mssql.Int);
ps.input('timestamp', mssql.DateTime);
ps.input('type', mssql.NVarChar);
ps.input('frr', mssql.NVarChar);
ps.prepare(sql, (err: any) => {
if (err) {
LendbookService.LOGGER.error('MSSQL prepare error', err);
}
else {
ps.execute(row, (err: any) => {
if (err) {
LendbookService.LOGGER.error('MSSQL execute error', err);
}
ps.unprepare((err: any) => {
if (err) {
LendbookService.LOGGER.error('MSSQL unprepare error', err);
}
});
});
}
});
return ps;
}
}
Versions: node: 6.9.1, mssql: 4.0.4
To avoid this error, you first need to call connect ([callback]) method and then move your prepared statement in its callback.
insert(row: object): any {
this.db.connect((err: any) => {
if (err) {
LendbookService.LOGGER.error('MSSQL connect error', err);
} else {
const sql = "INSERT INTO dbo.lendbook (rate, amount, period, timestamp, type, frr) VALUES (#rate, #amount, #period, #timestamp, #type, #frr)";
const ps = new mssql.PreparedStatement(this.db);
// ...
}
}
}

Resources